From f2ad9b27bbaec2adafdbf499eee750830a762d9d Mon Sep 17 00:00:00 2001
From: guowenxue <guowenxue@gmail.com>
Date: Thu, 09 Jan 2020 17:56:49 +0800
Subject: [PATCH] Add fl2440 linux-bsp folders

---
 linux-bsp/asm-study/myboot/include/common.h                         |   52 
 linux-bsp/asm-study/yaffs2/yaffs2/yaffs_ecc.c                       |  281 
 linux-bsp/asm-study/myboot/crc32.c                                  |  218 
 linux-bsp/asm-study/yaffs2/yaffs2/yaffs_attribs.c                   |  124 
 linux-bsp/asm-study/yaffs2/yaffs2/yaffs_ecc.h                       |   44 
 linux-bsp/driver/test/test_s3c_led.c                                |   81 
 linux-bsp/asm-study/yaffs2/bsp/makefile                             |  102 
 linux-bsp/asm-study/yaffs2/yaffs2/yaffs_attribs.h                   |   28 
 linux-bsp/driver/s3c_led.c                                          |  281 
 linux-bsp/asm-study/yaffs2/common/malloc.h                          |  947 +
 linux-bsp/asm-study/myboot/include/rsa.h                            |  208 
 linux-bsp/asm-study/asm/asm_c_buzzer/beep.c                         |   41 
 linux-bsp/asm-study/asm/asm_c_led/led.lds                           |   29 
 linux-bsp/driver/Makefile                                           |   46 
 linux-bsp/asm-study/asm/c_led/led.c                                 |   58 
 linux-bsp/asm-study/myboot/nand.h                                   |  271 
 linux-bsp/asm-study/myboot/led_beep.c                               |   56 
 linux-bsp/asm-study/yaffs2/yaffs2/yaffs_verify.h                    |   43 
 linux-bsp/asm-study/myboot/serial.c                                 |   74 
 linux-bsp/asm-study/yaffs2/yaffs2/yaffs_error.c                     |   58 
 linux-bsp/asm-study/myboot/xmodem.c                                 |  121 
 linux-bsp/asm-study/yaffs2/yaffs2/yaffs_osglue.c                    |  170 
 linux-bsp/asm-study/yaffs2/yaffs2/yaffs_verify.c                    |  529 
 linux-bsp/patches/gen_patch.sh                                      |   71 
 linux-bsp/asm-study/myboot/include/linux/stddef.h                   |   18 
 linux-bsp/asm-study/yaffs2/yaffs2/yaffscfg.h                        |   55 
 linux-bsp/asm-study/myboot/include/linux/string.h                   |   89 
 linux-bsp/asm-study/yaffs2/yaffs2/yaffs_osglue.h                    |   44 
 linux-bsp/asm-study/yaffs2/common/makefile                          |   97 
 linux-bsp/asm-study/yaffs2/yaffs2/yaffs_getblockinfo.h              |   35 
 linux-bsp/asm-study/asm/asm_c_led/start.S                           |   75 
 linux-bsp/asm-study/yaffs2/bootstrap.lds                            |   32 
 linux-bsp/driver/x86/Makefile                                       |   29 
 linux-bsp/asm-study/yaffs2/yaffs2/yaffs_allocator.c                 |  357 
 linux-bsp/driver/kernel_hello.c                                     |   35 
 linux-bsp/driver/test/test_plat_key.c                               |  279 
 linux-bsp/asm-study/yaffs2/yaffs2/yaffs_allocator.h                 |   30 
 linux-bsp/asm-study/yaffs2/yaffs2/yaffs_hweight.c                   |   53 
 linux-bsp/asm-study/yaffs2/bootstrap.c                              |  202 
 linux-bsp/asm-study/yaffs2/yaffs2/yaffs_flashif.h                   |   35 
 linux-bsp/asm-study/asm/c_led/makefile                              |   51 
 linux-bsp/asm-study/yaffs2/yaffs2/yaffs_hweight.h                   |   24 
 linux-bsp/driver/test/test_plat_led.c                               |   72 
 linux-bsp/asm-study/myboot/include/bignum.h                         |  380 
 linux-bsp/asm-study/yaffs2/common/stdio.h                           |   32 
 linux-bsp/asm-study/asm/asm_c_led/led.c                             |   77 
 linux-bsp/bootstrap/bootstrap.h                                     |  148 
 linux-bsp/asm-study/yaffs2/yaffs2/yaffs_list.h                      |  126 
 linux-bsp/asm-study/myboot/include/nand.h                           |  271 
 linux-bsp/asm-study/yaffs2/makefile                                 |  104 
 linux-bsp/asm-study/asm/asm_c_key_led/buzzer_led.c                  |   97 
 linux-bsp/asm-study/yaffs2/yaffs2/yaffsfs.c                         | 3461 ++++
 linux-bsp/asm-study/myboot/include/asm/sizes.h                      |   52 
 linux-bsp/asm-study/yaffs2/yaffs2/makefile                          |   97 
 linux-bsp/patches/u-boot-serial-patch/u-boot-2010.09-3-nand.patch   |  190 
 linux-bsp/driver/platdrv_led.c                                      |  297 
 linux-bsp/asm-study/myboot/bootstrap.c                              |  122 
 linux-bsp/asm-study/myboot/include/bn_asm.h                         |  549 
 linux-bsp/asm-study/yaffs2/yaffs2/yaffs_summary.c                   |  313 
 linux-bsp/asm-study/myboot/bignum.c                                 | 1842 ++
 linux-bsp/asm-study/myboot/bootstrap.lds                            |   32 
 linux-bsp/bootstrap/bootstrap.S                                     |  156 
 linux-bsp/asm-study/yaffs2/yaffs2/yaffs_summary.h                   |   37 
 linux-bsp/asm-study/myboot/include/s3c24x0.h                        | 1125 +
 linux-bsp/asm-study/myboot/rsa.c                                    |  602 
 linux-bsp/asm-study/yaffs2/yaffs2/yaffsfs.h                         |  233 
 linux-bsp/asm-study/asm/asm_led/led.S                               |   93 
 linux-bsp/asm-study/yaffs2/common/types.h                           |   99 
 linux-bsp/driver/platdev_led.h                                      |   67 
 linux-bsp/build.sh                                                  |  293 
 linux-bsp/driver/platdev_led.c                                      |  111 
 linux-bsp/patches/u-boot-2010.09-fl2440.patch                       | 2075 ++
 linux-bsp/patches/u-boot-serial-patch/u-boot-2010.09-1-basic.patch  | 1765 ++
 linux-bsp/asm-study/asm/asm_c_key_led/makefile                      |   51 
 linux-bsp/asm-study/yaffs2/yaffs2/yaffs_trace.h                     |   57 
 linux-bsp/asm-study/yaffs2/yaffs2/yaffs_k9f2g08.c                   |  144 
 linux-bsp/asm-study/yaffs2/yaffs2/yaffs_yaffs2.h                    |   39 
 linux-bsp/asm-study/yaffs2/bsp/s3c2440.h                            |  646 
 linux-bsp/asm-study/yaffs2/yaffs2/yaffs_guts.h                      |  977 +
 linux-bsp/asm-study/yaffs2/yaffs2/yaffs_checkptrw.c                 |  473 
 linux-bsp/asm-study/yaffs2/yaffs2/yaffs_checkptrw.h                 |   33 
 linux-bsp/asm-study/myboot/include/asm/posix_types.h                |   80 
 linux-bsp/asm-study/myboot/include/asm/hardware.h                   |   43 
 linux-bsp/asm-study/yaffs2/yaffs2/yaffs_yaffs2.c                    | 1532 ++
 linux-bsp/asm-study/yaffs2/yaffs2/yaffs_guts.c                      | 5053 ++++++
 linux-bsp/asm-study/myboot/include/linux/bitops.h                   |   75 
 linux-bsp/asm-study/yaffs2/yaffs2/yportenv.h                        |  318 
 linux-bsp/asm-study/yaffs2/yaffs2/yaffs_qsort.c                     |  163 
 linux-bsp/asm-study/myboot/include/s3c2440.h                        |  674 
 linux-bsp/asm-study/myboot/include/linux/config.h                   |    6 
 linux-bsp/asm-study/yaffs2/yaffs2/yaffs_k9f2g08.h                   |   13 
 linux-bsp/asm-study/yaffs2/bsp/s3c_board.c                          |  213 
 linux-bsp/patches/linux-3.0-fl2440.patch                            | 4153 +++++
 linux-bsp/asm-study/asm/asm_c_key_led/key.lds                       |   29 
 linux-bsp/asm-study/myboot/include/asm/types.h                      |   53 
 linux-bsp/asm-study/yaffs2/bsp/s3c_board.h                          |   34 
 linux-bsp/asm-study/myboot/include/linux/types.h                    |  131 
 linux-bsp/asm-study/myboot/interrupt.c                              |   39 
 linux-bsp/asm-study/myboot/start.S                                  |  348 
 linux-bsp/asm-study/asm/asm_c_key_led/start.S                       |   91 
 README.md                                                           |    2 
 linux-bsp/asm-study/yaffs2/common/string.c                          |  603 
 linux-bsp/asm-study/yaffs2/yaffs2/yaffs_nand.c                      |  120 
 linux-bsp/bootstrap/build.sh                                        |   52 
 linux-bsp/asm-study/yaffs2/common/dlmalloc.c                        | 3320 ++++
 linux-bsp/asm-study/yaffs2/common/string.h                          |   86 
 linux-bsp/asm-study/yaffs2/yaffs2/yaffs_nand.h                      |   38 
 linux-bsp/asm-study/yaffs2/bsp/eabi_compat.c                        |   29 
 linux-bsp/asm-study/myboot/makefile                                 |  118 
 linux-bsp/asm-study/yaffs2/yaffs2/yaffs_packedtags2.h               |   47 
 linux-bsp/asm-study/asm/asm_c_led/makefile                          |   51 
 linux-bsp/asm-study/yaffs2/yaffs2/yaffs_packedtags2.c               |  197 
 linux-bsp/asm-study/yaffs2/yaffs2/ydirectenv.h                      |   99 
 linux-bsp/asm-study/myboot/k9f2g08.c                                |  638 
 linux-bsp/asm-study/yaffs2/yaffs2/yaffs_tagscompat.h                |   36 
 linux-bsp/asm-study/asm/asm_c_buzzer/makefile                       |   51 
 linux-bsp/asm-study/yaffs2/yaffs2/yaffs_tagscompat.c                |  407 
 linux-bsp/asm-study/asm/asm_c_buzzer/start.S                        |   39 
 linux-bsp/patches/u-boot-serial-patch/u-boot-2010.09-2-dm9000.patch |   70 
 linux-bsp/asm-study/yaffs2/bsp/k9f2g08_api.h                        |   14 
 linux-bsp/driver/x86/kernel_hello.c                                 |    1 
 linux-bsp/asm-study/yaffs2/bsp/k9f2g08_api.c                        |  276 
 linux-bsp/asm-study/yaffs2/yaffs2/yaffs_flashif2.h                  |   35 
 linux-bsp/asm-study/yaffs2/yaffs2/yaffs_yaffs1.h                    |   22 
 linux-bsp/bootstrap/makefile                                        |   55 
 linux-bsp/driver/test/makefile                                      |   46 
 linux-bsp/asm-study/myboot/mem_init.S                               |  170 
 linux-bsp/asm-study/yaffs2/yaffs2/yaffs_yaffs1.c                    |  422 
 linux-bsp/driver/platdrv_key.c                                      |  339 
 linux-bsp/asm-study/asm/c_led/led.lds                               |   29 
 linux-bsp/asm-study/myboot/include/config.h                         |   36 
 linux-bsp/tarballs/rootfs.tar.bz2                                   |    0 
 linux-bsp/asm-study/myboot/common.c                                 |  413 
 linux-bsp/asm-study/myboot/include/asm/io.h                         |  330 
 linux-bsp/asm-study/yaffs2/yaffs2/yaffs_bitmap.h                    |   33 
 linux-bsp/asm-study/yaffs2/common/printf.c                          |  374 
 linux-bsp/asm-study/yaffs2/yaffs2/yaffs_bitmap.c                    |   97 
 linux-bsp/asm-study/yaffs2/yaffs2/yaffs_nameval.h                   |   28 
 linux-bsp/asm-study/asm/asm_led/makefile                            |   51 
 linux-bsp/asm-study/yaffs2/yaffs2/yaffscfg2k.c                      |  121 
 linux-bsp/patches/u-boot-serial-patch/u-boot-2010.09-4-linux.patch  |   91 
 linux-bsp/asm-study/asm/asm_c_buzzer/beep.lds                       |   29 
 linux-bsp/asm-study/yaffs2/yaffs2/yaffs_nameval.c                   |  208 
 linux-bsp/asm-study/myboot/include/asm/errno.h                      |  138 
 linux-bsp/asm-study/myboot/include/linux/time.h                     |  149 
 linux-bsp/asm-study/yaffs2/start.S                                  |   60 
 linux-bsp/asm-study/yaffs2/bsp/k9f2g08_s3c.h                        |  177 
 linux-bsp/asm-study/myboot/include/linux/ctype.h                    |   54 
 linux-bsp/asm-study/myboot/include/linux/posix_types.h              |   49 
 149 files changed, 45,708 insertions(+), 1 deletions(-)

diff --git a/README.md b/README.md
index 43e567e..f8365c9 100644
--- a/README.md
+++ b/README.md
@@ -1,4 +1,4 @@
 ## fl2440
 
-FL2440开发板源码
+FL2440 ARM Linux Board BSP and application
 
diff --git a/linux-bsp/asm-study/asm/asm_c_buzzer/beep.c b/linux-bsp/asm-study/asm/asm_c_buzzer/beep.c
new file mode 100644
index 0000000..5994d44
--- /dev/null
+++ b/linux-bsp/asm-study/asm/asm_c_buzzer/beep.c
@@ -0,0 +1,41 @@
+
+/***********************************************************************
+ *        File:  beep.c
+ *     Version:  1.0.0
+ *   Copyright:  2011 (c) Guo Wenxue <guowenxue@gmail.com>
+ * Description:  This C code used to turn buzzer on/off on FL2440 board
+ *   ChangeLog:  1, Release initial version on "Mon Mar 21 21:09:52 CST 2011"
+ *
+ ***********************************************************************/
+
+#define GPBCON   (*(unsigned long volatile *)0x56000010)
+#define GPBDAT   (*(unsigned long volatile *)0x56000014)
+#define GPBUP    (*(unsigned long volatile *)0x56000018)
+
+#define BEEP         0    /*Buzzer us GPB0 */
+#define LED0         5
+#define DELAY_TIME   40000000
+
+static inline void delay (unsigned long loops)
+{
+    __asm__ volatile ("1:\n"
+            "subs %0, %1, #1\n"
+            "bne 1b":"=r" (loops):"0" (loops));
+}
+
+int main(void)
+{
+    GPBCON = (GPBCON|0x3)&0x1; /* Set GPB0 as GPIO output mode(0x01) */
+    GPBUP &= ~1;               /* Enable pullup resister */
+
+    GPBDAT |= 0x560;
+    while(1)
+    {
+        GPBDAT &= ~(1<<BEEP);  /* Set Beep GPIO as low level */
+        delay(DELAY_TIME);
+
+        GPBDAT |= 1<<BEEP;     /* Set Beep GPIO as high level */
+        delay(DELAY_TIME);
+    }
+}
+
diff --git a/linux-bsp/asm-study/asm/asm_c_buzzer/beep.lds b/linux-bsp/asm-study/asm/asm_c_buzzer/beep.lds
new file mode 100644
index 0000000..9f03acd
--- /dev/null
+++ b/linux-bsp/asm-study/asm/asm_c_buzzer/beep.lds
@@ -0,0 +1,29 @@
+
+/***********************************************************************
+ *        File:  beep.lds
+ *     Version:  1.0.0
+ *   Copyright:  2011 (c) Guo Wenxue <guowenxue@gmail.com>
+ * Description:  Cross tool link text, refer to u-boot.lds
+ *   ChangeLog:  1, Release initial version on "Mon Mar 21 21:09:52 CST 2011"
+ *
+ ***********************************************************************/
+
+OUTPUT_FORMAT("elf32-littlearm", "elf32-littlearm", "elf32-littlearm")
+OUTPUT_ARCH(arm)
+ENTRY(_start)
+
+SECTIONS{
+    . = 0x33000000;
+    .text : {
+        *(.text)
+        *(.rodata)
+    }
+
+    .data ALIGN(4): {
+        *(.data)
+    }
+
+    .bss ALIGN(4): {
+        *(.bss)
+    }
+}
diff --git a/linux-bsp/asm-study/asm/asm_c_buzzer/makefile b/linux-bsp/asm-study/asm/asm_c_buzzer/makefile
new file mode 100644
index 0000000..80b687e
--- /dev/null
+++ b/linux-bsp/asm-study/asm/asm_c_buzzer/makefile
@@ -0,0 +1,51 @@
+# ***********************************************************************
+# *        File:  makefile
+# *     Version:  1.0.0
+# *   Copyright:  2011 (c) Guo Wenxue <guowenxue@gmail.com>
+# * Description:  Makefile used to cross compile the ASM and C source code
+# *   ChangeLog:  1, Release initial version on "Mon Mar 21 21:09:52 CST 2011"
+# *
+# ***********************************************************************
+
+BINAME = beep
+TEXTBASE = 0x33000000
+
+CROSS = /opt/xtools/arm920t/bin/arm-linux-
+CC      = $(CROSS)gcc
+LD      = $(CROSS)ld
+AR      = $(CROSS)ar
+OBJCOPY = $(CROSS)objcopy
+OBJDUMP = $(CROSS)objdump
+STRIP   = $(CROSS)strip
+READELF = $(CROSS)readelf
+
+CFLAGS  = -g -O2 -Wall -nostdinc -nostdlib -fno-builtin
+AFLAGS  = $(CFLAGS) -D__ASSEMBLY__
+
+LDSCRIPT = ${BINAME}.lds
+LDFLAGS  = -nostartfiles -T $(LDSCRIPT) -Ttext $(TEXTBASE)
+
+SRC_C   = $(wildcard *.c)
+SRC_S   = $(wildcard *.S)
+OBJ_C   = $(patsubst %.c,%.o,$(SRC_C)) 
+OBJ_S   = $(patsubst %.S,%.o,$(SRC_S)) 
+
+OBJ_ALL = $(OBJ_C) $(OBJ_S) 
+
+.PHONY : all
+all: ${OBJ_ALL}
+	${LD} $(LDFLAGS) -o ${BINAME}.elf ${OBJ_ALL}
+	${OBJCOPY} -O binary -S ${BINAME}.elf ${BINAME}.bin
+	rm -f *.elf *.o
+
+%.o: %.S
+	        $(CC) $(AFLAGS) -c -o $@ $<
+%.o: %.c
+	        $(CC) $(CFLAGS) -c -o $@ $<
+
+install:
+	cp ${BINAME}.bin ~/winxp -f --reply=yes
+
+clean:
+	rm -f *.elf *.o
+	rm -f ${BINAME}.bin
diff --git a/linux-bsp/asm-study/asm/asm_c_buzzer/start.S b/linux-bsp/asm-study/asm/asm_c_buzzer/start.S
new file mode 100644
index 0000000..0d9b4ab
--- /dev/null
+++ b/linux-bsp/asm-study/asm/asm_c_buzzer/start.S
@@ -0,0 +1,39 @@
+/***********************************************************************
+ *        File:  start.S
+ *     Version:  1.0.0
+ *   Copyright:  2011 (c) Guo Wenxue <guowenxue@gmail.com>
+ * Description:  This ASM used to disable watch dog and interrupt, then call C code to 
+ *               turn the buzzer on/off on FL2440 board.
+ *   ChangeLog:  1, Release initial version on "Mon Mar 21 21:09:52 CST 2011"
+ *
+ ***********************************************************************/
+
+#define pWTCON    0x53000000  /* Watch dog register address */
+#define INTMSK    0x4A000008  /* Interupt-Controller base addresses */
+#define INTSUBMSK 0x4A00001C
+
+    .text
+    .align 2
+    .global _start
+
+_start:
+
+    /* Disable watch dog */
+    ldr r0, =pWTCON  /*Save pwTCON address in r0*/
+    mov r1, #0x0     /*Set r1=0x0*/
+    str r1, [r0]     /*Move the data in r1 to the address specify by r0*/
+
+    /* mask all IRQs by setting all bits in the INTMR - default */
+    mov r1, #0xffffffff
+    ldr r0, =INTMSK
+    str r1, [r0] 
+
+    ldr r0, =INTSUBMSK
+    ldr r1, =0x7fff    /*There are 15 bits used in INTSUBMSK on S3C2440*/
+    str r1, [r0]
+
+    bl main
+
+halt_loop:
+    b halt_loop
+
diff --git a/linux-bsp/asm-study/asm/asm_c_key_led/buzzer_led.c b/linux-bsp/asm-study/asm/asm_c_key_led/buzzer_led.c
new file mode 100644
index 0000000..8198332
--- /dev/null
+++ b/linux-bsp/asm-study/asm/asm_c_key_led/buzzer_led.c
@@ -0,0 +1,97 @@
+
+/***********************************************************************
+ *        File:  buzzer_led.c
+ *     Version:  1.0.0
+ *   Copyright:  2011 (c) Guo Wenxue <guowenxue@gmail.com>
+ * Description:  This C code used to turn buzzer on/off on FL2440 board
+ *   ChangeLog:  1, Release initial version on "Tue Mar 22 21:58:24 CST 2011"
+ *
+ ***********************************************************************/
+
+#define GPBCON   (*(unsigned long volatile *)0x56000010)
+#define GPBDAT   (*(unsigned long volatile *)0x56000014)
+#define GPBUP    (*(unsigned long volatile *)0x56000018)
+
+#define BEEP     0    /* Buzzer use GPB0 */
+#define LED0     5    /* LED0 use GPB5*/
+#define LED1     6    /* LED1 use GPB6*/
+#define LED2     8    /* LED2 use GPB8*/
+#define LED3     10   /* LED3 use GPB10*/
+#define DELAY_TIME   40000000
+
+unsigned int led_gpio[4] = {5,6,8,10};
+
+static inline void delay (unsigned long loops)
+{
+    __asm__ volatile ("1:\n"
+            "subs %0, %1, #1\n"
+            "bne 1b":"=r" (loops):"0" (loops));
+}
+
+void init_led_buzzer(void)
+{
+    GPBCON = (GPBCON|0x333C03)&0x111401; /* Set GPB0,GPB5,GPB8,GPB10 as GPIO input mode */
+    GPBDAT |= 0x560;   /* Set GPB0,GPB5,GPB6,GPB8,GPB10 as high level */
+}
+
+void turn_led_on(int led)
+{
+    if(led > 3)
+        return;
+
+    /* Set GPIO port as low level */
+    GPBDAT = (GPBDAT & ( ~(1<<led_gpio[led])) );
+}
+
+/* Turn all LED off */
+void turn_all_led_off(void)
+{
+    GPBDAT |= 0x560; /* Set GPIO port as high level */
+}
+
+void turn_beep_on(void)
+{
+    GPBDAT |= 1<<BEEP;     /* Set Beep GPIO as high level, turn beep on */
+}
+
+void turn_beep_off(void)
+{
+    GPBDAT &= ~(1<<BEEP);  /* Set Beep GPIO as low level, turn beep off */
+}
+
+void turn_buzzer(int times)
+{
+    int      i;
+    for(i=0; i<times; i++)
+    {
+
+        turn_beep_on();
+        delay(DELAY_TIME);
+
+        turn_beep_off();
+        delay(DELAY_TIME);
+    }
+}
+
+void turn_led_buzzer_off(void)
+{
+    turn_all_led_off();
+    turn_beep_off();
+
+    return;
+}
+
+/* Input value $key is passed by start.S 
+ *
+ * Key2 pressed -> key=0, turn LED0 on, beep for 1 time
+ * Key3 pressed -> key=1, turn LED1 on, beep for 2 time
+ * Key4 pressed -> key=2, turn LED2 on, beep for 3 time
+ * Key5 pressed -> key=3, turn LED3 on, beep for 4 time
+ */
+
+void turn_led_buzzer_on(int key)
+{
+    turn_led_on(key);    /* Set correspond LED on */
+    turn_buzzer(key+1);  /* Let buzzer beep for $key times */
+}
+
diff --git a/linux-bsp/asm-study/asm/asm_c_key_led/key.lds b/linux-bsp/asm-study/asm/asm_c_key_led/key.lds
new file mode 100644
index 0000000..1291410
--- /dev/null
+++ b/linux-bsp/asm-study/asm/asm_c_key_led/key.lds
@@ -0,0 +1,29 @@
+
+/***********************************************************************
+ *        File:  key.lds
+ *     Version:  1.0.0
+ *   Copyright:  2011 (c) Guo Wenxue <guowenxue@gmail.com>
+ * Description:  Cross tool link text, refer to u-boot.lds
+ *   ChangeLog:  1, Release initial version on "Tue Mar 22 21:58:24 CST 2011"
+ *
+ ***********************************************************************/
+
+OUTPUT_FORMAT("elf32-littlearm", "elf32-littlearm", "elf32-littlearm")
+OUTPUT_ARCH(arm)
+ENTRY(_start)
+
+SECTIONS{
+    . = 0x33000000;
+    .text : {
+        *(.text)
+        *(.rodata)
+    }
+
+    .data ALIGN(4): {
+        *(.data)
+    }
+
+    .bss ALIGN(4): {
+        *(.bss)
+    }
+}
diff --git a/linux-bsp/asm-study/asm/asm_c_key_led/makefile b/linux-bsp/asm-study/asm/asm_c_key_led/makefile
new file mode 100644
index 0000000..fa634ce
--- /dev/null
+++ b/linux-bsp/asm-study/asm/asm_c_key_led/makefile
@@ -0,0 +1,51 @@
+# ***********************************************************************
+# *        File:  makefile
+# *     Version:  1.0.0
+# *   Copyright:  2011 (c) Guo Wenxue <guowenxue@gmail.com>
+# * Description:  Makefile used to cross compile the ASM and C source code
+# *   ChangeLog:  1, Release initial version on "Mon Mar 21 21:09:52 CST 2011"
+# *
+# ***********************************************************************
+
+BINAME = key
+TEXTBASE = 0x33000000
+
+CROSS = /opt/xtools/arm920t/bin/arm-linux-
+CC      = $(CROSS)gcc
+LD      = $(CROSS)ld
+AR      = $(CROSS)ar
+OBJCOPY = $(CROSS)objcopy
+OBJDUMP = $(CROSS)objdump
+STRIP   = $(CROSS)strip
+READELF = $(CROSS)readelf
+
+CFLAGS  = -g -O2 -Wall -nostdinc -nostdlib -fno-builtin
+AFLAGS  = $(CFLAGS) -D__ASSEMBLY__
+
+LDSCRIPT = ${BINAME}.lds
+LDFLAGS  = -nostartfiles -T $(LDSCRIPT) -Ttext $(TEXTBASE)
+
+SRC_C   = $(wildcard *.c)
+SRC_S   = $(wildcard *.S)
+OBJ_C   = $(patsubst %.c,%.o,$(SRC_C)) 
+OBJ_S   = $(patsubst %.S,%.o,$(SRC_S)) 
+
+OBJ_ALL = $(OBJ_C) $(OBJ_S) 
+
+.PHONY : all
+all: ${OBJ_ALL}
+	${LD} $(LDFLAGS) -o ${BINAME}.elf ${OBJ_ALL}
+	${OBJCOPY} -O binary -S ${BINAME}.elf ${BINAME}.bin
+	rm -f *.elf *.o
+
+%.o: %.S
+	        $(CC) $(AFLAGS) -c -o $@ $<
+%.o: %.c
+	        $(CC) $(CFLAGS) -c -o $@ $<
+
+install:
+	cp ${BINAME}.bin ~/winxp -f --reply=yes
+
+clean:
+	rm -f *.elf *.o
+	rm -f ${BINAME}.bin
diff --git a/linux-bsp/asm-study/asm/asm_c_key_led/start.S b/linux-bsp/asm-study/asm/asm_c_key_led/start.S
new file mode 100644
index 0000000..facae67
--- /dev/null
+++ b/linux-bsp/asm-study/asm/asm_c_key_led/start.S
@@ -0,0 +1,91 @@
+/***********************************************************************
+ *        File:  start.S
+ *     Version:  1.0.0
+ *   Copyright:  2011 (c) Guo Wenxue <guowenxue@gmail.com>
+ * Description:  This ASM used to detect the four keys status, if it's pressed down
+ *               then call the C function to turn the buzzer beep and LED on
+ *   ChangeLog:  1, Release initial version on "Tue Mar 22 21:58:24 CST 2011"
+ *
+ ***********************************************************************/
+
+#define pWTCON    0x53000000  /* Watch dog register address */
+#define INTMSK    0x4A000008  /* Interupt-Controller base addresses */
+#define INTSUBMSK 0x4A00001C
+
+#define GPFCON    0x56000050
+#define GPFDAT    0x56000054
+#define GPFUP     0x56000058
+
+#define KEY2      0  /*KEY S2 use GPF0/EINT0 port*/
+#define KEY3      2  /*KEY S3 use GPF2/EINT2 port*/
+#define KEY4      3  /*KEY S4 use GPF3/EINT3 port*/
+#define KEY5      4  /*KEY S5 use GPF4/EINT4 port*/
+
+    .text
+    .align 2
+    .global _start
+
+_start:
+
+    /* Disable watch dog */
+    ldr r0, =pWTCON  /*Save pwTCON address in r0*/
+    mov r1, #0x0     /*Set r1=0x0*/
+    str r1, [r0]     /*Move the data in r1 to the address specify by r0*/
+
+    /* mask all IRQs by setting all bits in the INTMR - default */
+    mov r1, #0xffffffff
+    ldr r0, =INTMSK
+    str r1, [r0] 
+
+    ldr r0, =INTSUBMSK
+    ldr r1, =0x7fff    /*There are 15 bits used in INTSUBMSK on S3C2440*/
+    str r1, [r0]
+
+    /*Set Beep GPIO port as GPIO input mode*/
+    ldr r0, =GPFCON  
+    ldr r1, [r0]
+    bic r1, r1, #0xf3    /* Set GPF0, GPF2, GPF3, as GPIO input mode(00)*/
+    bic r1, r1, #0x0300  /* Set GPF4 as GPIO input mode(00)*/
+    str r1, [r0]
+
+    bl init_led_buzzer  /*Call C function to init buzzer and LED GPIO port*/
+
+loop_detect:
+    bl turn_led_buzzer_off
+
+    ldr r1, =GPFDAT   /*Read the four key GPIO data port*/
+    ldr r2, [r1]
+
+    /*Check Key2 pressed down or not*/
+    mov r0, #0  /*Turn LED0 on*/
+    tst r2, #0x1
+    bleq led_beep_on
+
+    /*Check Key3 pressed down or not*/
+    mov r0, #1  /*Turn LED1 on*/
+    tst r2, #0x4
+    bleq led_beep_on
+
+    /*Check Key4 pressed down or not*/
+    mov r0, #2  /*Turn LED2 on*/
+    tst r2, #0x8
+    bleq led_beep_on
+
+    /*Check Key5 pressed down or not*/
+    mov r0, #3  /*Turn LED3 on*/
+    tst r2, #0x10
+    bleq led_beep_on
+
+    /*No key pressed, detect again*/
+    b loop_detect
+
+led_beep_on:
+    bl turn_led_buzzer_on  /*Turn buzzer beep*/
+    @mov pc, lr    /*Why mov lr, pc can not work?*/
+    b loop_detect
+
+
+    /*Won't come here*/
+halt_loop:
+    b halt_loop
+
diff --git a/linux-bsp/asm-study/asm/asm_c_led/led.c b/linux-bsp/asm-study/asm/asm_c_led/led.c
new file mode 100644
index 0000000..e6eb013
--- /dev/null
+++ b/linux-bsp/asm-study/asm/asm_c_led/led.c
@@ -0,0 +1,77 @@
+
+/***********************************************************************
+ *        File:  led.c
+ *     Version:  1.0.0
+ *   Copyright:  2011 (c) Guo Wenxue <guowenxue@gmail.com>
+ * Description:  This C code used to turn LED0~LED4 on on FL2440 board
+ *   ChangeLog:  1, Release initial version on "Mon Mar 21 21:09:52 CST 2011"
+ *
+ ***********************************************************************/
+
+#define GPBCON   (*(unsigned long volatile *)0x56000010)
+#define GPBDAT   (*(unsigned long volatile *)0x56000014)
+#define GPBUP    (*(unsigned long volatile *)0x56000018)
+
+#define LED0     5    /*LED0 use GPB5*/
+#define LED1     6    /*LED1 use GPB6*/
+#define LED2     8    /*LED2 use GPB8*/
+#define LED3     10   /*LED3 use GPB10*/
+
+#define DELAY_TIME   1000000
+
+static inline void delay (unsigned long loops)
+{
+    __asm__ volatile ("1:\n"
+        "subs %0, %1, #1\n"
+        "bne 1b":"=r" (loops):"0" (loops));
+}
+
+void led_init(void)
+{
+    /*  Set GPB5,GPB6,GPB8,GPB10 as GPIO mode(0x01) */ 
+    GPBCON = (GPBCON|0x333C00)&0x111400;
+    GPBUP = (GPBUP | 0x560);
+    /* Set GPB5,GPB6,GPB8,GPB10 as high level, to turn LED0,LED1,LED2,LED3 off */
+    GPBDAT = (GPBDAT | 0x560);
+}
+
+int main(void)
+{
+    led_init();
+    while(1)
+    {
+        /* Set GPB5,GPB6,GPB8,GPB10 as high level, to turn LED0,LED1,LED2,LED3 off */
+        GPBDAT = (GPBDAT | 0x560);
+        delay(DELAY_TIME);
+
+        /* Turn LED0 on */
+        GPBDAT = (GPBDAT & (~(1<<LED0)) );
+        delay(DELAY_TIME);
+
+        /* Turn LED1 on */
+        GPBDAT = (GPBDAT & (~(1<<LED1)) );
+        delay(DELAY_TIME);
+
+        /* Turn LED2 on */
+        GPBDAT = (GPBDAT & (~(1<<LED2)) );
+        delay(DELAY_TIME);
+
+        /* Turn LED3 on */
+        GPBDAT = (GPBDAT & (~(1<<LED3)) );
+        delay(DELAY_TIME);
+    }
+}
+
+void turn_led_on(int led)
+{
+     GPBDAT = (GPBDAT & (~(1<<led)) );
+     delay(DELAY_TIME);     
+}
+
+void turn_led_off(int led)
+{
+     /* Turn LED0 on */
+     GPBDAT = (GPBDAT | (1<<led) );
+     delay(DELAY_TIME);     
+}
+
diff --git a/linux-bsp/asm-study/asm/asm_c_led/led.lds b/linux-bsp/asm-study/asm/asm_c_led/led.lds
new file mode 100644
index 0000000..77023e5
--- /dev/null
+++ b/linux-bsp/asm-study/asm/asm_c_led/led.lds
@@ -0,0 +1,29 @@
+
+/***********************************************************************
+ *        File:  led.lds
+ *     Version:  1.0.0
+ *   Copyright:  2011 (c) Guo Wenxue <guowenxue@gmail.com>
+ * Description:  Cross tool link text, refer to u-boot.lds
+ *   ChangeLog:  1, Release initial version on "Mon Mar 21 21:09:52 CST 2011"
+ *
+ ***********************************************************************/
+
+OUTPUT_FORMAT("elf32-littlearm", "elf32-littlearm", "elf32-littlearm")
+OUTPUT_ARCH(arm)
+ENTRY(_start)
+
+SECTIONS{
+    . = 0x33000000;
+    .text : {
+        *(.text)
+        *(.rodata)
+    }
+
+    .data ALIGN(4): {
+        *(.data)
+    }
+
+    .bss ALIGN(4): {
+        *(.bss)
+    }
+}
diff --git a/linux-bsp/asm-study/asm/asm_c_led/makefile b/linux-bsp/asm-study/asm/asm_c_led/makefile
new file mode 100644
index 0000000..7d190b4
--- /dev/null
+++ b/linux-bsp/asm-study/asm/asm_c_led/makefile
@@ -0,0 +1,51 @@
+# ***********************************************************************
+# *        File:  makefile
+# *     Version:  1.0.0
+# *   Copyright:  2011 (c) Guo Wenxue <guowenxue@gmail.com>
+# * Description:  Makefile used to cross compile the ASM and C source code
+# *   ChangeLog:  1, Release initial version on "Mon Mar 21 21:09:52 CST 2011"
+# *
+# ***********************************************************************
+
+BINAME = led
+TEXTBASE = 0x33000000
+
+CROSS = /opt/xtools/arm920t/bin/arm-linux-
+CC      = $(CROSS)gcc
+LD      = $(CROSS)ld
+AR      = $(CROSS)ar
+OBJCOPY = $(CROSS)objcopy
+OBJDUMP = $(CROSS)objdump
+STRIP   = $(CROSS)strip
+READELF = $(CROSS)readelf
+
+CFLAGS  = -g -O2 -Wall -nostdinc -nostdlib -fno-builtin
+AFLAGS  = $(CFLAGS) -D__ASSEMBLY__
+
+LDSCRIPT = ${BINAME}.lds
+LDFLAGS  = -nostartfiles -T $(LDSCRIPT) -Ttext $(TEXTBASE)
+
+SRC_C   = $(wildcard *.c)
+SRC_S   = $(wildcard *.S)
+OBJ_C   = $(patsubst %.c,%.o,$(SRC_C)) 
+OBJ_S   = $(patsubst %.S,%.o,$(SRC_S)) 
+
+OBJ_ALL = $(OBJ_C) $(OBJ_S) 
+
+.PHONY : all
+all: ${OBJ_ALL}
+	${LD} $(LDFLAGS) -o ${BINAME}.elf ${OBJ_ALL}
+	${OBJCOPY} -O binary -S ${BINAME}.elf ${BINAME}.bin
+	rm -f *.elf *.o
+
+%.o: %.S
+	        $(CC) $(AFLAGS) -c -o $@ $<
+%.o: %.c
+	        $(CC) $(CFLAGS) -c -o $@ $<
+
+install:
+	cp ${BINAME}.bin ~/winxp -f --reply=yes
+
+clean:
+	rm -f *.elf *.o
+	rm -f ${BINAME}.bin
diff --git a/linux-bsp/asm-study/asm/asm_c_led/start.S b/linux-bsp/asm-study/asm/asm_c_led/start.S
new file mode 100644
index 0000000..031b07a
--- /dev/null
+++ b/linux-bsp/asm-study/asm/asm_c_led/start.S
@@ -0,0 +1,75 @@
+/***********************************************************************
+ *        File:  start.S
+ *     Version:  1.0.0
+ *   Copyright:  2011 (c) Guo Wenxue <guowenxue@gmail.com>
+ * Description:  This ASM used to disable watch dog and interrupt, then call C code to 
+ *               turn the four LEDs on/off on FL2440 board.
+ *   ChangeLog:  1, Release initial version on "Mon Mar 21 21:09:52 CST 2011"
+ *
+ ***********************************************************************/
+
+#define pWTCON    0x53000000  /* Watch dog register address */
+#define INTMSK    0x4A000008  /* Interupt-Controller base addresses */
+#define INTSUBMSK 0x4A00001C
+
+#define LED0     5    /*LED0 use GPB5*/
+#define LED1     6    /*LED1 use GPB6*/
+#define LED2     8    /*LED2 use GPB8*/
+#define LED3     10   /*LED3 use GPB10*/
+
+
+    .text
+    .align 2
+    .global _start
+
+_start:
+
+    /* Disable watch dog */
+    ldr r0, =pWTCON  /*Save pwTCON address in r0*/
+    mov r1, #0x0     /*Set r1=0x0*/
+    str r1, [r0]     /*Move the data in r1 to the address specify by r0*/
+
+
+    /* mask all IRQs by setting all bits in the INTMR - default */
+    mov r1, #0xffffffff
+    ldr r0, =INTMSK
+    str r1, [r0] 
+
+    ldr r0, =INTSUBMSK
+    ldr r1, =0x7fff    /*There are 15 bits used in INTSUBMSK on S3C2440*/
+    str r1, [r0]
+    
+    bl  led_init
+
+loop:
+    mov r0,#LED0
+    bl turn_led_on
+
+    mov r0,#LED1
+    bl turn_led_on
+
+    mov r0,#LED2
+    bl turn_led_on
+
+    mov r0,#LED3
+    bl turn_led_on
+
+    mov r0,#LED0
+    bl turn_led_off
+
+    mov r0,#LED1
+    bl turn_led_off
+
+    mov r0,#LED2
+    bl turn_led_off
+
+    mov r0,#LED3
+    bl turn_led_off
+
+    b loop
+
+    @bl main
+
+halt_loop:
+    b halt_loop
+
diff --git a/linux-bsp/asm-study/asm/asm_led/led.S b/linux-bsp/asm-study/asm/asm_led/led.S
new file mode 100644
index 0000000..7fd3fcd
--- /dev/null
+++ b/linux-bsp/asm-study/asm/asm_led/led.S
@@ -0,0 +1,93 @@
+/***********************************************************************
+ *        File:  led.S
+ *     Version:  1.0.0
+ *   Copyright:  2011 (c) Guo Wenxue <guowenxue@gmail.com>
+ * Description:  This ASM code used to turn LED0~LED4 on/off on FL2440 board
+ *   ChangeLog:  1, Release initial version on "Sun Mar 20 18:41:04 CST 2011"
+ *
+ ***********************************************************************/
+
+
+#define GPBCON   0x56000010
+#define GPBDAT   0x56000014
+#define GPBUP    0x56000018
+
+#define OUTPUT   0x01   /*Set GPIO port as output mode*/
+#define INPUT    0x00   /*Set GPIO port as input mode*/
+
+#define BEEP     0      /*On FL2440 board, LED0 use GPB0*/
+#define LED0     5      /*On FL2440 board, LED0 use GPB5*/
+#define LED1     6      /*On FL2440 board, LED0 use GPB6*/
+#define LED2     8      /*On FL2440 board, LED0 use GPB8*/
+#define LED3     10     /*On FL2440 board, LED0 use GPB10*/
+
+#define DELAY    0X1000000
+
+    .text
+    .align 2
+    .global _start
+
+_start:
+    /*Set GPIO5, GPIO6, GPIO8, GPIO10 as GPIO OUTPUT mode*/
+    ldr     r0, =GPBCON
+    ldr     r1, [r0]
+    bic     r1, r1, #0x3c00      /*Set GPBCON for GPIO5,GPIO6 as 0x00 */
+    orr     r1, r1, #0x1400      /*Set GPBCON for GPIO5,GPIO6 as GPIOOUT, 0x01*/
+    bic     r1, r1, #0x00330000  /*Set GPBCON for GPIO8,GPIO10 as 0x00*/
+    orr     r1, r1, #0x00110000  /*Set GPBCON for GPIO8,GPIO10 as GPIOOUT, 0x01*/
+    str     r1, [r0]
+
+    /*Set internal pullup resister*/
+    ldr     r0, =GPBUP
+    ldr     r1, [r0]
+    orr     r1, r1, #0x0560     /*Set bit 5,6,8,10, disable pullup resister*/
+    @bic     r1, r1, #0x0560      /*Clear bit 5,6,8,10, enable pullup resister*/
+    str     r1, [r0] 
+
+
+loopled:
+    /*Turn off LED5, LED6, LED8, LED10*/
+    ldr     r2, =GPBDAT
+    ldr     r3, [r2]
+    orr     r3, r3, #0x0560     /*Set bit 5,6,8,10 as high level*/
+    str     r3, [r2]  
+    ldr     r0, =DELAY          /*Sleep for a while*/
+    bl      delay
+
+    /*Turn on LED0*/
+    ldr     r3, [r2]
+    bic     r3, r3, #(1<<LED0)  /*Clear bit 5, set GPB5 as low level*/
+    str     r3, [r2]  
+    ldr     r0, =DELAY          /*Sleep for a while*/
+    bl      delay
+
+    /*Turn on LED1*/
+    ldr     r3, [r2]
+    bic     r3, r3, #(1<<LED1)  /*Clear bit 6, set GPB6 as low level*/
+    str     r3, [r2]  
+    ldr     r0, =DELAY          /*Sleep for a while*/
+    bl      delay
+
+    /*Turn on LED2*/
+    ldr     r3, [r2]
+    bic     r3, r3, #(1<<LED2)  /*Clear bit 8, set GPB8 as low level*/
+    str     r3, [r2]  
+    ldr     r0, =DELAY          /*Sleep for a while*/
+    bl      delay
+
+    /*Turn on LED3*/
+    ldr     r3, [r2]
+    bic     r3, r3, #(1<<LED3)  /*Clear bit 10, set GPB10 as low level*/
+    str     r3, [r2]  
+    ldr     r0, =DELAY          /*Sleep for a while*/
+    bl      delay
+
+
+    b       loopled             /*Loop running LED*/
+
+delay:
+    sub     r0, r0, #1
+    cmp     r0, #0x0
+    bne     delay
+    mov     pc, lr
+
diff --git a/linux-bsp/asm-study/asm/asm_led/makefile b/linux-bsp/asm-study/asm/asm_led/makefile
new file mode 100644
index 0000000..07cbaea
--- /dev/null
+++ b/linux-bsp/asm-study/asm/asm_led/makefile
@@ -0,0 +1,51 @@
+# ***********************************************************************
+# *        File:  makefile
+# *     Version:  1.0.0
+# *   Copyright:  2011 (c) Guo Wenxue <guowenxue@gmail.com>
+# * Description:  Makefile used to cross compile the ASM and C source code
+# *   ChangeLog:  1, Release initial version on "Mon Mar 21 21:09:52 CST 2011"
+# *
+# ***********************************************************************
+
+BINAME = led
+TEXTBASE = 0x33000000
+#TEXTBASE =0
+
+CROSS = /opt/xtools/arm920t/bin/arm-linux-
+CC      = $(CROSS)gcc
+LD      = $(CROSS)ld
+AR      = $(CROSS)ar
+OBJCOPY = $(CROSS)objcopy
+OBJDUMP = $(CROSS)objdump
+STRIP   = $(CROSS)strip
+READELF = $(CROSS)readelf
+
+CFLAGS  = -g -O2 -Wall -nostdinc -nostdlib -fno-builtin
+AFLAGS  = $(CFLAGS) -D__ASSEMBLY__
+
+LDFLAGS  = -Ttext $(TEXTBASE)
+
+SRC_C   = $(wildcard *.c)
+SRC_S   = $(wildcard *.S)
+OBJ_C   = $(patsubst %.c,%.o,$(SRC_C)) 
+OBJ_S   = $(patsubst %.S,%.o,$(SRC_S)) 
+
+OBJ_ALL = $(OBJ_C) $(OBJ_S) 
+
+.PHONY : all
+all: ${OBJ_ALL}
+	${LD} $(LDFLAGS) -o ${BINAME}.elf ${OBJ_ALL}
+	${OBJCOPY} -O binary -S ${BINAME}.elf ${BINAME}.bin
+	rm -f *.elf *.o
+
+%.o: %.S
+	        $(CC) $(AFLAGS) -c -o $@ $<
+%.o: %.c
+	        $(CC) $(CFLAGS) -c -o $@ $<
+
+install:
+	cp ${BINAME}.bin ~/winxp -f --reply=yes
+
+clean:
+	rm -f *.elf *.o
+	rm -f ${BINAME}.bin
diff --git a/linux-bsp/asm-study/asm/c_led/led.c b/linux-bsp/asm-study/asm/c_led/led.c
new file mode 100644
index 0000000..2043ed0
--- /dev/null
+++ b/linux-bsp/asm-study/asm/c_led/led.c
@@ -0,0 +1,58 @@
+
+/***********************************************************************
+ *        File:  led.c
+ *     Version:  1.0.0
+ *   Copyright:  2011 (c) Guo Wenxue <guowenxue@gmail.com>
+ * Description:  This C code used to turn LED0~LED4 on on FL2440 board
+ *   ChangeLog:  1, Release initial version on "Mon Mar 21 21:09:52 CST 2011"
+ *
+ ***********************************************************************/
+
+#define GPBCON   (*(unsigned long volatile *)0x56000010)
+#define GPBDAT   (*(unsigned long volatile *)0x56000014)
+#define GPBUP    (*(unsigned long volatile *)0x56000018)
+
+#define LED0     5    /*LED0 use GPB5*/
+#define LED1     6    /*LED1 use GPB6*/
+#define LED2     8    /*LED2 use GPB8*/
+#define LED3     10   /*LED3 use GPB10*/
+
+#define DELAY_TIME   20000000
+
+static inline void delay (unsigned long loops)
+{
+    __asm__ volatile ("1:\n"
+        "subs %0, %1, #1\n"
+        "bne 1b":"=r" (loops):"0" (loops));
+}
+
+int main(void)
+{
+    /*  Set GPB5,GPB6,GPB8,GPB10 as GPIO mode(0x01) */ 
+    GPBCON = (GPBCON|0x333C00)&0x111400;
+    GPBUP = (GPBUP | 0x560);
+
+    while(1)
+    {
+        /* Set GPB5,GPB6,GPB8,GPB10 as high level, to turn LED0,LED1,LED2,LED3 off */
+        GPBDAT = (GPBDAT | 0x560);
+        delay(DELAY_TIME);
+
+        /* Turn LED0 on */
+        GPBDAT = (GPBDAT & (~(1<<LED0)) );
+        delay(DELAY_TIME);
+
+        /* Turn LED1 on */
+        GPBDAT = (GPBDAT & (~(1<<LED1)) );
+        delay(DELAY_TIME);
+
+        /* Turn LED2 on */
+        GPBDAT = (GPBDAT & (~(1<<LED2)) );
+        delay(DELAY_TIME);
+
+        /* Turn LED3 on */
+        GPBDAT = (GPBDAT & (~(1<<LED3)) );
+        delay(DELAY_TIME);
+    }
+}
+
diff --git a/linux-bsp/asm-study/asm/c_led/led.lds b/linux-bsp/asm-study/asm/c_led/led.lds
new file mode 100644
index 0000000..2e497ba
--- /dev/null
+++ b/linux-bsp/asm-study/asm/c_led/led.lds
@@ -0,0 +1,29 @@
+
+/***********************************************************************
+ *        File:  led.lds
+ *     Version:  1.0.0
+ *   Copyright:  2011 (c) Guo Wenxue <guowenxue@gmail.com>
+ * Description:  Cross tool link text, refer to u-boot.lds
+ *   ChangeLog:  1, Release initial version on "Mon Mar 21 21:09:52 CST 2011"
+ *
+ ***********************************************************************/
+
+OUTPUT_FORMAT("elf32-littlearm", "elf32-littlearm", "elf32-littlearm")
+OUTPUT_ARCH(arm)
+ENTRY(main)
+
+SECTIONS{
+    . = 0x33000000;
+    .text : {
+        *(.text)
+        *(.rodata)
+    }
+
+    .data ALIGN(4): {
+        *(.data)
+    }
+
+    .bss ALIGN(4): {
+        *(.bss)
+    }
+}
diff --git a/linux-bsp/asm-study/asm/c_led/makefile b/linux-bsp/asm-study/asm/c_led/makefile
new file mode 100644
index 0000000..a07273f
--- /dev/null
+++ b/linux-bsp/asm-study/asm/c_led/makefile
@@ -0,0 +1,51 @@
+# ***********************************************************************
+# *        File:  makefile
+# *     Version:  1.0.0
+# *   Copyright:  2011 (c) Guo Wenxue <guowenxue@gmail.com>
+# * Description:  Makefile used to cross compile the ASM and C source code
+# *   ChangeLog:  1, Release initial version on "Mon Mar 21 21:09:52 CST 2011"
+# *
+# ***********************************************************************
+
+BINAME = led
+TEXTBASE = 0x33000000
+
+CROSS = /opt/xtools/arm920t/bin/arm-linux-
+CC      = $(CROSS)gcc
+LD      = $(CROSS)ld
+AR      = $(CROSS)ar
+OBJCOPY = $(CROSS)objcopy
+OBJDUMP = $(CROSS)objdump
+STRIP   = $(CROSS)strip
+READELF = $(CROSS)readelf
+
+CFLAGS  = -g -O2 -Wall -nostdinc -nostdlib -fno-builtin
+AFLAGS  = $(CFLAGS) -D__ASSEMBLY__
+
+LDSCRIPT = ${BINAME}.lds
+LDFLAGS  = -T $(LDSCRIPT) -Ttext $(TEXTBASE)
+
+SRC_C   = $(wildcard *.c)
+SRC_S   = $(wildcard *.S)
+OBJ_C   = $(patsubst %.c,%.o,$(SRC_C)) 
+OBJ_S   = $(patsubst %.S,%.o,$(SRC_S)) 
+
+OBJ_ALL = $(OBJ_C) $(OBJ_S) 
+
+.PHONY : all
+all: ${OBJ_ALL}
+	${LD} $(LDFLAGS) -o ${BINAME}.elf ${OBJ_ALL}
+	${OBJCOPY} -O binary -S ${BINAME}.elf ${BINAME}.bin
+	rm -f *.elf *.o
+
+%.o: %.S
+	        $(CC) $(AFLAGS) -c -o $@ $<
+%.o: %.c
+	        $(CC) $(CFLAGS) -c -o $@ $<
+
+install:
+	cp ${BINAME}.bin ~/winxp -f --reply=yes
+
+clean:
+	rm -f *.elf *.o
+	rm -f ${BINAME}.bin
diff --git a/linux-bsp/asm-study/myboot/bignum.c b/linux-bsp/asm-study/myboot/bignum.c
new file mode 100644
index 0000000..7e6ce77
--- /dev/null
+++ b/linux-bsp/asm-study/myboot/bignum.c
@@ -0,0 +1,1842 @@
+/*
+ *  Multi-precision integer library
+ *
+ *  Copyright (C) 2006  Christophe Devine
+ *
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Lesser General Public
+ *  License, version 2.1 as published by the Free Software Foundation.
+ *
+ *  This library is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser General Public
+ *  License along with this library; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+ *  MA  02110-1301  USA
+ */
+/*
+ *  This MPI implementation is based on:
+ *
+ *  http://www.cacr.math.uwaterloo.ca/hac/about/chap14.pdf
+ *  http://math.libtomcrypt.com/files/tommath.pdf
+ */
+
+#ifndef _CRT_SECURE_NO_DEPRECATE
+#define _CRT_SECURE_NO_DEPRECATE 1
+#endif
+#include <common.h>
+#include <bignum.h>
+
+/*
+ * Bits/chars to # of limbs conversion
+ */
+#define BITS_TO_LIMBS(i)  (((i) + biL - 1) / biL)
+#define CHARS_TO_LIMBS(i) (((i) + ciL - 1) / ciL)
+
+/*
+ * Initialize one or more mpi
+ */
+void mpi_init( mpi *X, ... )
+{
+    va_list args;
+
+    va_start( args, X );
+
+    while( X != NULL )
+    {
+        memset( X, 0, sizeof( mpi ) );
+        X = va_arg( args, mpi* );
+    }
+
+    va_end( args );
+}
+
+/*
+ * Unallocate one or more mpi
+ */
+void mpi_free( mpi *X, ... )
+{
+    va_list args;
+
+    va_start( args, X );
+
+    while( X != NULL )
+    {
+        if( X->p != NULL )
+        {
+            memset( X->p, 0, X->n * ciL );
+            free( X->p );
+        }
+
+        memset( X, 0, sizeof( mpi ) );
+
+        X = va_arg( args, mpi* );
+    }
+
+    va_end( args );
+}
+
+/*
+ * Enlarge X to the specified # of limbs
+ */
+int mpi_grow( mpi *X, int nblimbs )
+{
+    int n = X->n;
+
+    if( n < nblimbs )
+    {
+        if( X->s == 0 )
+            X->s = 1;
+
+        X->n = nblimbs;
+        X->p = (t_int *) realloc( X->p, X->n * ciL );
+
+        if( X->p == NULL )
+            return( 1 );
+
+        memset( X->p + n, 0, ( X->n - n ) * ciL );
+    }
+
+    return( 0 );
+}
+
+/*
+ * Copy the contents of Y into X
+ */
+int mpi_copy( mpi *X, mpi *Y )
+{
+    int ret, i;
+
+    if( X == Y )
+        return( 0 );
+
+    for( i = Y->n - 1; i > 0; i-- )
+        if( Y->p[i] != 0 )
+            break;
+    i++;
+
+    X->s = Y->s;
+
+    CHK( mpi_grow( X, i ) );
+
+    memset( X->p, 0, X->n * ciL );
+    memcpy( X->p, Y->p, i * ciL );
+
+cleanup:
+
+    return( ret );
+}
+
+/*
+ * Swap the contents of X and Y
+ */
+void mpi_swap( mpi *X, mpi *Y )
+{
+    mpi T;
+
+    memcpy( &T, X , sizeof( mpi ) );
+    memcpy( X , Y , sizeof( mpi ) );
+    memcpy( Y , &T, sizeof( mpi ) );
+}
+
+/*
+ * Set value from integer
+ */
+int mpi_lset( mpi *X, int z )
+{
+    int ret;
+
+    CHK( mpi_grow( X, 1 ) );
+    memset( X->p, 0, X->n * ciL );
+    X->p[0] = ( z < 0 ) ? -z : z;
+    X->s    = ( z < 0 ) ? -1 : 1;
+
+cleanup:
+
+    return( ret );
+}
+
+/*
+ * Convert an ASCII character to digit value
+ */
+static int mpi_get_digit( t_int *d, int radix, char c )
+{
+    *d = 16;
+
+    if( c >= 0x30 && c <= 0x39 ) *d = c - 0x30;
+    if( c >= 0x41 && c <= 0x46 ) *d = c - 0x37;
+    if( c >= 0x61 && c <= 0x66 ) *d = c - 0x57;
+
+    if( *d >= (t_int) radix )
+        return( ERR_MPI_INVALID_CHARACTER );
+
+    return( 0 );
+}
+
+/*
+ * Set value from string
+ */
+int mpi_read( mpi *X, char *s, int radix )
+{
+    int ret, i, j, n;
+    t_int d;
+    mpi T;
+
+    if( radix < 2 || radix > 16 )
+        return( ERR_MPI_INVALID_PARAMETER );
+
+    mpi_init( &T, NULL );
+
+    if( radix == 16 )
+    {
+        n = BITS_TO_LIMBS( strlen(s) << 2 );
+
+        CHK( mpi_grow( X, n ) );
+        CHK( mpi_lset( X, 0 ) );
+
+        for( i = strlen( s ) - 1, j = 0; i >= 0; i--, j++ )
+        {
+            if( i == 0 && s[i] == '-' )
+            {
+                X->s = -1;
+                break;
+            }
+
+            CHK( mpi_get_digit( &d, radix, s[i] ) );
+            X->p[j / (ciL * 2)] |= d << ( (j % (ciL * 2)) << 2 );
+        }
+    }
+    else
+    {
+        CHK( mpi_lset( X, 0 ) );
+
+        for( i = 0; i < (int) strlen( s ); i++ )
+        {
+            if( i == 0 && s[i] == '-' )
+            {
+                X->s = -1;
+                continue;
+            }
+
+            CHK( mpi_get_digit( &d, radix, s[i] ) );
+            CHK( mpi_mul_int( &T, X, radix ) );
+            CHK( mpi_add_int( X, &T, d ) );
+        }
+    }
+
+cleanup:
+
+    mpi_free( &T, NULL );
+    return( ret );
+}
+
+/*
+ * Helper to display the digits high-order first
+ */
+static int mpi_recurse_showf( mpi *X, int radix, FILE *fout )
+{
+    int ret;
+    t_int r;
+
+    if( radix < 2 || radix > 16 )
+        return( ERR_MPI_INVALID_PARAMETER );
+
+    CHK( mpi_mod_int( &r, X, radix ) );
+    CHK( mpi_div_int( X, NULL, X, radix ) );
+
+    if( mpi_cmp_int( X, 0 ) != 0 )
+        CHK( mpi_recurse_showf( X, radix, fout ) );
+
+    if( fout != NULL )
+        fprintf( fout, "%c", ( r < 10 ) ? ( (char) r + 0x30 )
+                                        : ( (char) r + 0x37 ) );
+    else
+        printf( "%c", ( r < 10 ) ? ( (char) r + 0x30 )
+                                 : ( (char) r + 0x37 ) );
+
+cleanup:
+
+    return( ret );
+}
+
+/*
+ * Print the value of X into fout
+ */
+int mpi_showf( char *name, mpi *X, int radix, FILE *fout )
+{
+    int ret, i, j, k, l;
+    mpi T;
+
+    if( radix < 2 || radix > 16 )
+        return( ERR_MPI_INVALID_PARAMETER );
+
+    mpi_init( &T, NULL );
+
+    if( fout != NULL )
+        fprintf( fout, "%s%c", name, ( X->s == -1 ) ? '-' : ' ' );
+    else
+        printf( "%s%c", name, ( X->s == -1 ) ? '-' : ' ' );
+
+    if( radix == 16 )
+    {
+        ret = 0;
+
+        for( i = X->n - 1, l = 0; i >= 0; i-- )
+        {
+            for( j = ciL - 1; j >= 0; j-- )
+            {
+                k = ( X->p[i] >> (j << 3) ) & 0xFF;
+
+                if( k == 0 && l == 0 && (i + j) != 0 )
+                    continue;
+
+                if( fout != NULL )
+                    fprintf( fout, "%02X", k );
+                else
+                    printf( "%02X", k );
+
+                l = 1;
+            }
+        }
+    }
+    else
+    {
+        CHK( mpi_copy( &T, X ) );
+        CHK( mpi_recurse_showf( &T, radix, fout ) );
+    }
+
+    if( fout != NULL )
+        fprintf( fout, "\n" );
+    else
+        printf( "\n" );
+
+cleanup:
+
+    mpi_free( &T, NULL );
+    return( ret );
+}
+
+/*
+ * Print the value of X on the console
+ */
+int mpi_show( char *name, mpi *X, int radix )
+{
+    return( mpi_showf( name, X, radix, NULL ) );
+}
+
+/*
+ * Import an unsigned value from binary data
+ */
+int mpi_import( mpi *X, unsigned char *buf, int buflen )
+{
+    int ret, i, j, n;
+
+    for( n = 0; n < buflen; n++ )
+        if( buf[n] != 0 )
+            break;
+
+    CHK( mpi_grow( X, CHARS_TO_LIMBS(buflen - n) ) );
+    CHK( mpi_lset( X, 0 ) );
+
+    for( i = buflen - 1, j = 0; i >= n; i--, j++ )
+        X->p[j / ciL] |= (t_int) buf[i] << ((j % ciL ) << 3);
+
+cleanup:
+
+    return( ret );
+}
+
+/*
+ * Export an unsigned value into binary data
+ */
+int mpi_export( mpi *X, unsigned char *buf, int *buflen )
+{
+    int i, j, n, ilen;
+
+    n = ( mpi_size( X ) + 7 ) >> 3;
+	ilen = n;
+
+    if( *buflen < n )
+    {
+        *buflen = n;
+        return( ERR_MPI_BUFFER_TOO_SMALL );
+    }
+	//*buflen = ilen;
+	
+
+    memset( buf, 0, *buflen );
+
+    for( i = *buflen - 1, j = 0; n > 0; i--, j++, n-- )
+        buf[i] = (unsigned char) (X->p[j / ciL] >> ((j % ciL) << 3));
+
+
+
+    return( 0 );
+}
+
+/*
+ * Return the actual size in bits (without leading 0s)
+ */
+int mpi_size( mpi *X )
+{
+    int i, j;
+
+    for( i = X->n - 1; i > 0; i-- )
+        if( X->p[i] != 0 )
+            break;
+
+    for( j = biL - 1; j >= 0; j-- )
+        if( ( ( X->p[i] >> j ) & 1 ) != 0 )
+            break;
+
+    return( ( i * biL ) + j + 1 );
+}
+
+/*
+ * Return the number of least significant bits
+ */
+int mpi_lsb( mpi *X )
+{
+    int i, j, count = 0;
+
+    for( i = 0; i < X->n; i++ )
+        for( j = 0; j < (int) biL; j++, count++ )
+            if( ( ( X->p[i] >> j ) & 1 ) != 0 )
+                return( count );
+
+    return( 0 );
+}
+
+/*
+ * Left-shift: X <<= count
+ */
+int mpi_shift_l( mpi *X, int count )
+{
+    int ret, i, v0, t1;
+    t_int r0 = 0, r1;
+
+    v0 = count /  biL;
+    t1 = count & (biL - 1);
+
+    i = mpi_size( X ) + count;
+
+    if( X->n * (int) biL < i )
+        CHK( mpi_grow( X, BITS_TO_LIMBS( i ) ) );
+
+    ret = 0;
+
+    /*
+     * shift by count / limb_size
+     */
+    if( v0 > 0 )
+    {
+        for( i = X->n - 1; i >= v0; i-- )
+            X->p[i] = X->p[i - v0];
+
+        for( ; i >= 0; i-- )
+            X->p[i] = 0;
+    }
+
+    /*
+     * shift by count % limb_size
+     */
+    if( t1 > 0 )
+    {
+        for( i = v0; i < X->n; i++ )
+        {
+            r1 = X->p[i] >> (biL - t1);
+            X->p[i] <<= t1;
+            X->p[i] |= r0;
+            r0 = r1;
+        }
+    }
+
+cleanup:
+
+    return( ret );
+}
+
+/*
+ * Right-shift: X >>= count
+ */
+int mpi_shift_r( mpi *X, int count )
+{
+    int i, v0, v1;
+    t_int r0 = 0, r1;
+
+    v0 = count /  biL;
+    v1 = count & (biL - 1);
+
+    /*
+     * shift by count / limb_size
+     */
+    if( v0 > 0 )
+    {
+        for( i = 0; i < X->n - v0; i++ )
+            X->p[i] = X->p[i + v0];
+
+        for( ; i < X->n; i++ )
+            X->p[i] = 0;
+    }
+
+    /*
+     * shift by count % limb_size
+     */
+    if( v1 > 0 )
+    {
+        for( i = X->n - 1; i >= 0; i-- )
+        {
+            r1 = X->p[i] << (biL - v1);
+            X->p[i] >>= v1;
+            X->p[i] |= r0;
+            r0 = r1;
+        }
+    }
+
+    return( 0 );
+}
+
+/*
+ * Compare unsigned values
+ */
+int mpi_cmp_abs( mpi *X, mpi *Y )
+{
+    int i, j;
+
+    for( i = X->n - 1; i >= 0; i-- )
+        if( X->p[i] != 0 )
+            break;
+
+    for( j = Y->n - 1; j >= 0; j-- )
+        if( Y->p[j] != 0 )
+            break;
+
+    if( i < 0 && j < 0 )
+        return( 0 );
+
+    if( i > j ) return(  1 );
+    if( j > i ) return( -1 );
+
+    for( ; i >= 0; i-- )
+    {
+        if( X->p[i] > Y->p[i] ) return(  1 );
+        if( X->p[i] < Y->p[i] ) return( -1 );
+    }
+
+    return( 0 );
+}
+
+/*
+ * Compare signed values
+ */
+int mpi_cmp_mpi( mpi *X, mpi *Y )
+{
+    int i, j;
+
+    for( i = X->n - 1; i >= 0; i-- )
+        if( X->p[i] != 0 )
+            break;
+
+    for( j = Y->n - 1; j >= 0; j-- )
+        if( Y->p[j] != 0 )
+            break;
+
+    if( i < 0 && j < 0 )
+        return( 0 );
+
+    if( i > j ) return(  X->s );
+    if( j > i ) return( -X->s );
+
+    if( X->s > 0 && Y->s < 0 ) return(  1 );
+    if( Y->s > 0 && X->s < 0 ) return( -1 );
+
+    for( ; i >= 0; i-- )
+    {
+        if( X->p[i] > Y->p[i] ) return(  X->s );
+        if( X->p[i] < Y->p[i] ) return( -X->s );
+    }
+
+    return( 0 );
+}
+
+/*
+ * Compare signed values
+ */
+int mpi_cmp_int( mpi *X, int z )
+{
+    mpi Y;
+    t_int p[1];
+
+    *p  = ( z < 0 ) ? -z : z;
+    Y.s = ( z < 0 ) ? -1 : 1;
+    Y.n = 1;
+    Y.p = p;
+
+    return( mpi_cmp_mpi( X, &Y ) );
+}
+
+/*
+ * Unsigned addition: X = |A| + |B|  (HAC 14.7)
+ */
+int mpi_add_abs( mpi *X, mpi *A, mpi *B )
+{
+    int ret, i, j;
+    t_int *o, *p, c;
+
+    if( X == B )
+    {
+        mpi *T = A; A = X; B = T;
+    }
+
+    if( X != A )
+        CHK( mpi_copy( X, A ) );
+
+    for( j = B->n - 1; j >= 0; j-- )
+        if( B->p[j] != 0 )
+            break;
+
+    CHK( mpi_grow( X, j + 1 ) );
+
+    o = B->p; p = X->p; c = 0;
+
+    for( i = 0; i <= j; i++, o++, p++ )
+    {
+        *p +=  c; c  = ( *p <  c );
+        *p += *o; c += ( *p < *o );
+    }
+
+    while( c != 0 )
+    {
+        if( i >= X->n )
+        {
+            CHK( mpi_grow( X, i + 1 ) );
+            p = X->p + i;
+        }
+
+        *p += c; c = ( *p < c ); i++;
+    }
+
+cleanup:
+
+    return( ret );
+}
+
+/*
+ * Helper for mpi substraction
+ */
+static void mpi_sub_hlp( int n, t_int *s, t_int *d )
+{
+    int i;
+    t_int c, z;
+
+    for( i = c = 0; i < n; i++, s++, d++ )
+    {
+        z = ( *d <  c );     *d -=  c;
+        c = ( *d < *s ) + z; *d -= *s;
+    }
+
+    while( c != 0 )
+    {
+        z = ( *d < c ); *d -= c;
+        c = z; i++; d++;
+    }
+}
+
+/*
+ * Unsigned substraction: X = |A| - |B|  (HAC 14.9)
+ */
+int mpi_sub_abs( mpi *X, mpi *A, mpi *B )
+{
+    mpi TB;
+    int ret, n;
+
+    if( mpi_cmp_abs( A, B ) < 0 )
+        return( ERR_MPI_NEGATIVE_VALUE );
+
+    mpi_init( &TB, NULL );
+
+    if( X == B )
+    {
+        CHK( mpi_copy( &TB, B ) );
+        B = &TB;
+    }
+
+    if( X != A )
+        CHK( mpi_copy( X, A ) );
+
+    ret = 0;
+
+    for( n = B->n - 1; n >= 0; n-- )
+        if( B->p[n] != 0 )
+            break;
+
+    mpi_sub_hlp( n + 1, B->p, X->p );
+
+cleanup:
+
+    mpi_free( &TB, NULL );
+    return( ret );
+}
+
+/*
+ * Signed addition: X = A + B
+ */
+int mpi_add_mpi( mpi *X, mpi *A, mpi *B )
+{
+    int ret, s = A->s;
+
+    if( A->s * B->s < 0 )
+    {
+        if( mpi_cmp_abs( A, B ) >= 0 )
+        {
+            CHK( mpi_sub_abs( X, A, B ) );
+            X->s =  s;
+        }
+        else
+        {
+            CHK( mpi_sub_abs( X, B, A ) );
+            X->s = -s;
+        }
+    }
+    else
+    {
+        CHK( mpi_add_abs( X, A, B ) );
+        X->s = s;
+    }
+
+cleanup:
+
+    return( ret );
+}
+
+/*
+ * Signed substraction: X = A - B
+ */
+int mpi_sub_mpi( mpi *X, mpi *A, mpi *B )
+{
+    int ret, s = A->s;
+
+    if( A->s * B->s > 0 )
+    {
+        if( mpi_cmp_abs( A, B ) >= 0 )
+        {
+            CHK( mpi_sub_abs( X, A, B ) );
+            X->s =  s;
+        }
+        else
+        {
+            CHK( mpi_sub_abs( X, B, A ) );
+            X->s = -s;
+        }
+    }
+    else
+    {
+        CHK( mpi_add_abs( X, A, B ) );
+        X->s = s;
+    }
+
+cleanup:
+
+    return( ret );
+}
+
+/*
+ * Signed addition: X = A + b
+ */
+int mpi_add_int( mpi *X, mpi *A, int b )
+{
+    mpi _B;
+    t_int p[1];
+
+    p[0] = ( b < 0 ) ? -b : b;
+    _B.s = ( b < 0 ) ? -1 : 1;
+    _B.n = 1;
+    _B.p = p;
+
+    return( mpi_add_mpi( X, A, &_B ) );
+}
+
+/*
+ * Signed substraction: X = A - b
+ */
+int mpi_sub_int( mpi *X, mpi *A, int b )
+{
+    mpi _B;
+    t_int p[1];
+
+    p[0] = ( b < 0 ) ? -b : b;
+    _B.s = ( b < 0 ) ? -1 : 1;
+    _B.n = 1;
+    _B.p = p;
+
+    return( mpi_sub_mpi( X, A, &_B ) );
+}
+
+/*
+ * Helper for mpi multiplication
+ */ 
+static void mpi_mul_hlp( int i, t_int *s, t_int *d, t_int b )
+{
+    t_int c = 0;
+
+#if defined(MULADDC_HUIT)
+
+    for( ; i >= 8; i -= 8 )
+    {
+        MULADDC_INIT
+        MULADDC_HUIT
+        MULADDC_STOP
+    }
+
+    for( ; i > 0; i-- )
+    {
+        MULADDC_INIT
+        MULADDC_CORE
+        MULADDC_STOP
+    }
+
+#else
+    if( i == 32 )
+    {
+        MULADDC_INIT
+        MULADDC_CORE   MULADDC_CORE
+        MULADDC_CORE   MULADDC_CORE   MULADDC_CORE
+        MULADDC_CORE   MULADDC_CORE   MULADDC_CORE
+
+        MULADDC_CORE   MULADDC_CORE
+        MULADDC_CORE   MULADDC_CORE   MULADDC_CORE
+        MULADDC_CORE   MULADDC_CORE   MULADDC_CORE
+        MULADDC_CORE   MULADDC_CORE   MULADDC_CORE
+        MULADDC_CORE   MULADDC_CORE   MULADDC_CORE
+        MULADDC_CORE   MULADDC_CORE
+
+        MULADDC_CORE   MULADDC_CORE   MULADDC_CORE
+        MULADDC_CORE   MULADDC_CORE   MULADDC_CORE
+        MULADDC_CORE   MULADDC_CORE
+        MULADDC_STOP
+    }
+    else
+    {
+        if( i == 16 )
+        {
+            MULADDC_INIT
+            MULADDC_CORE   MULADDC_CORE
+            MULADDC_CORE   MULADDC_CORE
+            MULADDC_CORE   MULADDC_CORE
+            MULADDC_CORE   MULADDC_CORE
+
+            MULADDC_CORE   MULADDC_CORE
+            MULADDC_CORE   MULADDC_CORE
+            MULADDC_CORE   MULADDC_CORE
+            MULADDC_CORE   MULADDC_CORE
+            MULADDC_STOP
+        }
+        else
+        {
+            for( ; i >= 8; i -= 8 )
+            {
+                MULADDC_INIT
+                MULADDC_CORE   MULADDC_CORE
+                MULADDC_CORE   MULADDC_CORE
+
+                MULADDC_CORE   MULADDC_CORE
+                MULADDC_CORE   MULADDC_CORE
+                MULADDC_STOP
+            }
+
+            for( ; i > 0; i-- )
+            {
+                MULADDC_INIT
+                MULADDC_CORE
+                MULADDC_STOP
+            }
+        }
+    }
+#endif
+
+    do {
+        *d += c; c = ( *d < c ); d++;
+    }
+    while( c != 0 );
+}
+
+/*
+ * Baseline multiplication: X = A * B  (HAC 14.12)
+ */
+int mpi_mul_mpi( mpi *X, mpi *A, mpi *B )
+{
+    int ret, i, j;
+    mpi TA, TB;
+
+    mpi_init( &TA, &TB, NULL );
+
+    if( X == A ) { CHK( mpi_copy( &TA, A ) ); A = &TA; }
+    if( X == B ) { CHK( mpi_copy( &TB, B ) ); B = &TB; }
+
+    for( i = A->n - 1; i >= 0; i-- )
+        if( A->p[i] != 0 )
+            break;
+
+    for( j = B->n - 1; j >= 0; j-- )
+        if( B->p[j] != 0 )
+            break;
+
+    CHK( mpi_grow( X, i + j + 2 ) );
+    CHK( mpi_lset( X, 0 ) );
+
+    for( i++; j >= 0; j-- )
+        mpi_mul_hlp( i, A->p, X->p + j, B->p[j] );
+
+    X->s = A->s * B->s;
+
+cleanup:
+
+    mpi_free( &TB, &TA, NULL );
+    return( ret );
+}
+
+/*
+ * Baseline multiplication: X = A * b
+ */
+int mpi_mul_int( mpi *X, mpi *A, t_int b )
+{
+    mpi _B;
+    t_int p[1];
+
+    _B.s = 1;
+    _B.n = 1;
+    _B.p = p;
+    p[0] = b;
+
+    return( mpi_mul_mpi( X, A, &_B ) );
+}
+
+/*
+ * Division by mpi: A = Q * B + R  (HAC 14.20)
+ */
+int mpi_div_mpi( mpi *Q, mpi *R, mpi *A, mpi *B )
+{
+    int ret, i, n, t, k;
+    mpi X, Y, Z, T1, T2;
+
+    if( mpi_cmp_int( B, 0 ) == 0 )
+        return( ERR_MPI_DIVISION_BY_ZERO );
+
+    mpi_init( &X, &Y, &Z, &T1, &T2, NULL );
+
+    if( mpi_cmp_abs( A, B ) < 0 )
+    {
+        if( Q != NULL ) CHK( mpi_lset( Q, 0 ) );
+        if( R != NULL ) CHK( mpi_copy( R, A ) );
+        return( 0 );
+    }
+
+    CHK( mpi_copy( &X, A ) );
+    CHK( mpi_copy( &Y, B ) );
+    X.s = Y.s = 1;
+
+    CHK( mpi_grow( &Z, A->n + 2 ) );
+    CHK( mpi_lset( &Z,  0 ) );
+    CHK( mpi_grow( &T1, 2 ) );
+    CHK( mpi_grow( &T2, 3 ) );
+
+    k = mpi_size( &Y ) % biL;
+    if( k < (int) biL - 1 )
+    {
+        k = biL - 1 - k;
+        CHK( mpi_shift_l( &X, k ) );
+        CHK( mpi_shift_l( &Y, k ) );
+    }
+    else k = 0;
+
+    n = X.n - 1;
+    t = Y.n - 1;
+    mpi_shift_l( &Y, biL * (n - t) );
+    while( mpi_cmp_mpi( &X, &Y ) >= 0 )
+    {
+        Z.p[n - t]++;
+        mpi_sub_mpi( &X, &X, &Y );
+    }
+    mpi_shift_r( &Y, biL * (n - t) );
+
+    for( i = n; i > t ; i-- )
+    {
+        if( X.p[i] >= Y.p[t] )
+            Z.p[i - t - 1] = ~0;
+        else
+        {
+#if defined(HAVE_LONGLONG)
+            t_dbl r;
+
+            r  = (t_dbl) X.p[i] << biL;
+            r |= (t_dbl) X.p[i - 1];
+            r /= Y.p[t];
+            if( r > ((t_dbl) 1 << biL) - 1)
+                r = ((t_dbl) 1 << biL) - 1;
+
+            Z.p[i - t - 1] = (t_int) r;
+#else
+            /*
+             * __udiv_qrnnd_c, from GMP/longlong.h
+             */
+            t_int q0, q1, r0, r1;
+            t_int d0, d1, d, m;
+
+            d  = Y.p[t];
+            d0 = ( d << biH ) >> biH;
+            d1 = ( d >> biH );
+
+            q1 = X.p[i] / d1;
+            r1 = X.p[i] - d1 * q1;
+            r1 <<= biH;
+            r1 |= ( X.p[i - 1] >> biH );
+
+            m = q1 * d0;
+            if( r1 < m )
+            {
+                q1--, r1 += d;
+                while( r1 >= d && r1 < m )
+                    q1--, r1 += d;
+            }
+            r1 -= m;
+
+            q0 = r1 / d1;
+            r0 = r1 - d1 * q0;
+            r0 <<= biH;
+            r0 |= ( X.p[i - 1] << biH ) >> biH;
+
+            m = q0 * d0;
+            if( r0 < m )
+            {
+                q0--, r0 += d;
+                while( r0 >= d && r0 < m )
+                    q0--, r0 += d;
+            }
+            r0 -= m;
+
+            Z.p[i - t - 1] = ( q1 << biH ) | q0;
+#endif
+        }
+
+        Z.p[i - t - 1]++;
+        do
+        {
+            Z.p[i - t - 1]--;
+
+            CHK( mpi_lset( &T1, 0 ) );
+            T1.p[0] = (t < 1) ? 0 : Y.p[t - 1];
+            T1.p[1] = Y.p[t];
+            CHK( mpi_mul_int( &T1, &T1, Z.p[i - t - 1] ) );
+
+            CHK( mpi_lset( &T2, 0 ) );
+            T2.p[0] = (i < 2) ? 0 : X.p[i - 2];
+            T2.p[1] = (i < 1) ? 0 : X.p[i - 1];
+            T2.p[2] = X.p[i];
+        }
+        while( mpi_cmp_mpi( &T1, &T2 ) > 0 );
+
+        CHK( mpi_mul_int( &T1, &Y, Z.p[i - t - 1] ) );
+        CHK( mpi_shift_l( &T1,  biL * (i - t - 1) ) );
+        CHK( mpi_sub_mpi( &X, &X, &T1 ) );
+
+        if( mpi_cmp_int( &X, 0 ) < 0 )
+        {
+            CHK( mpi_copy( &T1, &Y ) );
+            CHK( mpi_shift_l( &T1, biL * (i - t - 1) ) );
+            CHK( mpi_add_mpi( &X, &X, &T1 ) );
+            Z.p[i - t - 1]--;
+        }
+    }
+
+    if( Q != NULL )
+    {
+        mpi_copy( Q, &Z );
+        Q->s = A->s * B->s;
+    }
+
+    if( R != NULL )
+    {
+        mpi_shift_r( &X, k );
+        mpi_copy( R, &X );
+
+        R->s = A->s;
+        if( mpi_cmp_int( R, 0 ) == 0 )
+            R->s = 1;
+    }
+
+cleanup:
+
+    mpi_free( &X, &Y, &Z, &T1, &T2, NULL );
+    return( ret );
+}
+
+/*
+ * Division by int: A = Q * b + R
+ *
+ * Returns 0 if successful
+ *         1 if memory allocation failed
+ *         ERR_MPI_DIVISION_BY_ZERO if b == 0
+ */
+int mpi_div_int( mpi *Q, mpi *R, mpi *A, int b )
+{
+    mpi _B;
+    t_int p[1];
+
+    p[0] = ( b < 0 ) ? -b : b;
+    _B.s = ( b < 0 ) ? -1 : 1;
+    _B.n = 1;
+    _B.p = p;
+
+    return( mpi_div_mpi( Q, R, A, &_B ) );
+}
+
+/*
+ * Modulo: R = A mod B
+ */
+int mpi_mod_mpi( mpi *R, mpi *A, mpi *B )
+{
+    int ret;
+
+    CHK( mpi_div_mpi( NULL, R, A, B ) );
+
+    while( mpi_cmp_int( R, 0 ) < 0 )
+      CHK( mpi_add_mpi( R, R, B ) );
+
+    while( mpi_cmp_mpi( R, B ) >= 0 )
+      CHK( mpi_sub_mpi( R, R, B ) );
+
+cleanup:
+
+    return( ret );
+}
+
+/*
+ * Modulo: r = A mod b
+ */
+int mpi_mod_int( t_int *r, mpi *A, int b )
+{
+    int i;
+    t_int x, y, z;
+
+    if( b == 0 )
+        return( ERR_MPI_DIVISION_BY_ZERO );
+
+    if( b < 0 )
+        b = -b;
+
+    /*
+     * handle trivial cases
+     */
+    if( b == 1 ) { *r = 0;           return( 0 ); }
+    if( b == 2 ) { *r = A->p[0] & 1; return( 0 ); }
+
+    /*
+     * general case
+     */
+    for( i = A->n - 1, y = 0; i >= 0; i-- )
+    {
+        x  = A->p[i];
+        y  = ( y << biH ) | ( x >> biH );
+        z  = y / b;
+        y -= z * b;
+
+        x <<= biH;
+        y  = ( y << biH ) | ( x >> biH );
+        z  = y / b;
+        y -= z * b;
+    }
+
+    *r = y;
+
+    return( 0 );
+}
+
+/*
+ * Fast Montgomery initialization (thanks to Tom St Denis)
+ */
+static void mpi_montg_init( t_int *mm, mpi *N )
+{
+    t_int x, m0 = N->p[0];
+
+    x  = m0;
+    x += ((m0 + 2) & 4) << 1;
+    x *= (2 - (m0 * x));
+
+    if( biL >= 16 ) x *= (2 - (m0 * x));
+    if( biL >= 32 ) x *= (2 - (m0 * x));
+    if( biL >= 64 ) x *= (2 - (m0 * x));
+
+    *mm = ~x + 1;
+}
+
+/*
+ * Montgomery multiplication: A = A * B * R^-1 mod N  (HAC 14.36)
+ */
+static void mpi_montmul( mpi *A, mpi *B, mpi *N, t_int mm, mpi *T )
+{
+    int i, n, m;
+    t_int u0, u1, *d;
+
+    memset( T->p, 0, ciL * T->n );
+
+    d = T->p;
+    n = N->n;
+    m = ( B->n < n ) ? B->n : n;
+
+    for( i = 0; i < n; i++ )
+    {
+        /*
+         * T = (T + u0*B + u1*N) / 2^biL
+         */
+        u0 = A->p[i];
+        u1 = ( d[0] + u0 * B->p[0] ) * mm;
+
+        mpi_mul_hlp( m, B->p, d, u0 );
+        mpi_mul_hlp( n, N->p, d, u1 );
+
+        *d++ = u0; d[n + 1] = 0;
+    }
+
+    memcpy( A->p, d, ciL * (n + 1) );
+
+    if( mpi_cmp_abs( A, N ) >= 0 )
+        mpi_sub_hlp( n, N->p, A->p );
+    else
+        /* prevent timing attacks */
+        mpi_sub_hlp( n, A->p, T->p );
+}
+
+/*
+ * Montgomery reduction: A = A * R^-1 mod N
+ */
+static void mpi_montred( mpi *A, mpi *N, t_int mm, mpi *T )
+{
+    t_int z = 1;
+    mpi U;
+
+    U.n = U.s = z;
+    U.p = &z;
+
+    mpi_montmul( A, &U, N, mm, T );
+}
+
+/*
+ * Sliding-window exponentiation: X = A^E mod N  (HAC 14.85)
+ */
+int mpi_exp_mod( mpi *X, mpi *A, mpi *E, mpi *N, mpi *_RR )
+{
+    int ret, i, j, wsize, wbits;
+    int bufsize, nblimbs, nbits;
+    t_int ei, mm, state;
+    mpi RR, T, W[64];
+
+    if( mpi_cmp_int( N, 0 ) < 0 || ( N->p[0] & 1 ) == 0 )
+        return( ERR_MPI_INVALID_PARAMETER );
+
+    /*
+     * Init temps and window size
+     */
+    mpi_montg_init( &mm, N );
+    mpi_init( &RR, &T, NULL );
+    memset( W, 0, sizeof( W ) );
+
+    i = mpi_size( E );
+
+    wsize = ( i > 671 ) ? 6 : ( i > 239 ) ? 5 :
+            ( i >  79 ) ? 4 : ( i >  23 ) ? 3 : 1;
+
+    j = N->n + 1;
+    CHK( mpi_grow( X, j ) );
+    CHK( mpi_grow( &W[1],  j ) );
+    CHK( mpi_grow( &T, j * 2 ) );
+
+    /*
+     * If 1st call, pre-compute R^2 mod N
+     */
+    if( _RR == NULL || _RR->p == NULL )
+    {
+        CHK( mpi_lset( &RR, 1 ) );
+        CHK( mpi_shift_l( &RR, N->n * 2 * biL ) );
+        CHK( mpi_mod_mpi( &RR, &RR, N ) );
+
+        if( _RR != NULL )
+            memcpy( _RR, &RR, sizeof( mpi ) );
+    }
+    else
+        memcpy( &RR, _RR, sizeof( mpi ) );
+
+    /*
+     * W[1] = A * R^2 * R^-1 mod N = A * R mod N
+     */
+    if( mpi_cmp_mpi( A, N ) >= 0 )
+        mpi_mod_mpi( &W[1], A, N );
+    else   mpi_copy( &W[1], A );
+
+    mpi_montmul( &W[1], &RR, N, mm, &T );
+
+    /*
+     * X = R^2 * R^-1 mod N = R mod N
+     */
+    CHK( mpi_copy( X, &RR ) );
+    mpi_montred( X, N, mm, &T );
+
+    if( wsize > 1 )
+    {
+        /*
+         * W[1 << (wsize - 1)] = W[1] ^ (wsize - 1)
+         */
+        j =  1 << (wsize - 1);
+
+        CHK( mpi_grow( &W[j], N->n + 1 ) );
+        CHK( mpi_copy( &W[j], &W[1]    ) );
+
+        for( i = 0; i < wsize - 1; i++ )
+            mpi_montmul( &W[j], &W[j], N, mm, &T );
+    
+        /*
+         * W[i] = W[i - 1] * W[1]
+         */
+        for( i = j + 1; i < (1 << wsize); i++ )
+        {
+            CHK( mpi_grow( &W[i], N->n + 1 ) );
+            CHK( mpi_copy( &W[i], &W[i - 1] ) );
+
+            mpi_montmul( &W[i], &W[1], N, mm, &T );
+        }
+    }
+
+    nblimbs = E->n;
+    bufsize = 0;
+    nbits   = 0;
+    wbits   = 0;
+    state   = 0;
+
+    while( 1 )
+    {
+        if( bufsize == 0 )
+        {
+            if( nblimbs-- == 0 )
+                break;
+
+            bufsize = sizeof( t_int ) << 3;
+        }
+
+        bufsize--;
+
+        ei = (E->p[nblimbs] >> bufsize) & 1;
+
+        /*
+         * skip leading 0s
+         */
+        if( ei == 0 && state == 0 )
+            continue;
+
+        if( ei == 0 && state == 1 )
+        {
+            /*
+             * out of window, square X
+             */
+            mpi_montmul( X, X, N, mm, &T );
+            continue;
+        }
+
+        /*
+         * add ei to current window
+         */
+        state = 2;
+
+        nbits++;
+        wbits |= (ei << (wsize - nbits));
+
+        if( nbits == wsize )
+        {
+            /*
+             * X = X^wsize R^-1 mod N
+             */
+            for( i = 0; i < wsize; i++ )
+                mpi_montmul( X, X, N, mm, &T );
+
+            /*
+             * X = X * W[wbits] R^-1 mod N
+             */
+            mpi_montmul( X, &W[wbits], N, mm, &T );
+
+            state--;
+            nbits = 0;
+            wbits = 0;
+        }
+    }
+
+    /*
+     * process the remaining bits
+     */
+    for( i = 0; i < nbits; i++ )
+    {
+        mpi_montmul( X, X, N, mm, &T );
+
+        wbits <<= 1;
+
+        if( (wbits & (1 << wsize)) != 0 )
+            mpi_montmul( X, &W[1], N, mm, &T );
+    }
+
+    /*
+     * X = A^E * R * R^-1 mod N = A^E mod N
+     */
+    mpi_montred( X, N, mm, &T );
+
+cleanup:
+
+    for( i = (1 << (wsize - 1)); i < (1 << wsize); i++ )
+        mpi_free( &W[i], NULL );
+
+    if( _RR != NULL )
+         mpi_free( &W[1], &T, NULL );
+    else mpi_free( &W[1], &T, &RR, NULL );
+
+    return( ret );
+}
+
+/*
+ * Greatest common divisor: G = gcd(A, B)  (HAC 14.54)
+ */
+int mpi_gcd( mpi *G, mpi *A, mpi *B )
+{
+    int ret, count;
+    mpi TG, TA, TB;
+
+    mpi_init( &TG, &TA, &TB, NULL );
+
+    CHK( mpi_lset( &TG, 1 ) );
+    CHK( mpi_copy( &TA, A ) );
+    CHK( mpi_copy( &TB, B ) );
+
+    TA.s = TB.s = 1;
+
+    count = ( mpi_lsb( &TA ) < mpi_lsb( &TB ) )
+            ? mpi_lsb( &TA ) : mpi_lsb( &TB );
+
+    CHK( mpi_shift_l( &TG, count ) );
+    CHK( mpi_shift_r( &TA, count ) );
+    CHK( mpi_shift_r( &TB, count ) );
+
+    while( mpi_cmp_int( &TA, 0 ) != 0 )
+    {
+        while( ( TA.p[0] & 1 ) == 0 ) CHK( mpi_shift_r( &TA, 1 ) );
+        while( ( TB.p[0] & 1 ) == 0 ) CHK( mpi_shift_r( &TB, 1 ) );
+
+        if( mpi_cmp_mpi( &TA, &TB ) >= 0 )
+        {
+            CHK( mpi_sub_abs( &TA, &TA, &TB ) );
+            CHK( mpi_shift_r( &TA, 1 ) );
+        }
+        else
+        {
+            CHK( mpi_sub_abs( &TB, &TB, &TA ) );
+            CHK( mpi_shift_r( &TB, 1 ) );
+        }
+    }
+
+    CHK( mpi_mul_mpi( G, &TG, &TB ) );
+
+cleanup:
+
+    mpi_free( &TB, &TA, &TG, NULL );
+    return( ret );
+}
+
+/*
+ * Modular inverse: X = A^-1 mod N  (HAC 14.61 / 14.64)
+ */
+int mpi_inv_mod( mpi *X, mpi *A, mpi *N )
+{
+    int ret;
+    mpi G, TA, TU, U1, U2, TB, TV, V1, V2;
+
+    if( mpi_cmp_int( N, 0 ) <= 0 )
+        return( ERR_MPI_INVALID_PARAMETER );
+
+    mpi_init( &TA, &TU, &U1, &U2, &G,
+              &TB, &TV, &V1, &V2, NULL );
+
+    CHK( mpi_gcd( &G, A, N ) );
+
+    if( mpi_cmp_int( &G, 1 ) != 0 )
+    {
+        ret = ERR_MPI_NOT_INVERTIBLE;
+        goto cleanup;
+    }
+
+    CHK( mpi_mod_mpi( &TA, A, N ) );
+    CHK( mpi_copy( &TU, &TA ) );
+    CHK( mpi_copy( &TB, N ) );
+    CHK( mpi_copy( &TV, N ) );
+
+    CHK( mpi_lset( &U1, 1 ) );
+    CHK( mpi_lset( &U2, 0 ) );
+    CHK( mpi_lset( &V1, 0 ) );
+    CHK( mpi_lset( &V2, 1 ) );
+
+    do
+    {
+        while( ( TU.p[0] & 1 ) == 0 )
+        {
+            CHK( mpi_shift_r( &TU, 1 ) );
+
+            if( ( U1.p[0] & 1 ) != 0 || ( U2.p[0] & 1 ) != 0 )
+            {
+                CHK( mpi_add_mpi( &U1, &U1, &TB ) );
+                CHK( mpi_sub_mpi( &U2, &U2, &TA ) );
+            }
+
+            CHK( mpi_shift_r( &U1, 1 ) );
+            CHK( mpi_shift_r( &U2, 1 ) );
+        }
+
+        while( ( TV.p[0] & 1 ) == 0 )
+        {
+            CHK( mpi_shift_r( &TV, 1 ) );
+
+            if( ( V1.p[0] & 1 ) != 0 || ( V2.p[0] & 1 ) != 0 )
+            {
+                CHK( mpi_add_mpi( &V1, &V1, &TB ) );
+                CHK( mpi_sub_mpi( &V2, &V2, &TA ) );
+            }
+
+            CHK( mpi_shift_r( &V1, 1 ) );
+            CHK( mpi_shift_r( &V2, 1 ) );
+        }
+
+        if( mpi_cmp_mpi( &TU, &TV ) >= 0 )
+        {
+            CHK( mpi_sub_mpi( &TU, &TU, &TV ) );
+            CHK( mpi_sub_mpi( &U1, &U1, &V1 ) );
+            CHK( mpi_sub_mpi( &U2, &U2, &V2 ) );
+        }
+        else
+        {
+            CHK( mpi_sub_mpi( &TV, &TV, &TU ) );
+            CHK( mpi_sub_mpi( &V1, &V1, &U1 ) );
+            CHK( mpi_sub_mpi( &V2, &V2, &U2 ) );
+        }
+    }
+    while( mpi_cmp_int( &TU, 0 ) != 0 );
+
+    while( mpi_cmp_int( &V1, 0 ) < 0 )
+      CHK( mpi_add_mpi( &V1, &V1, N ) );
+
+    while( mpi_cmp_mpi( &V1, N ) >= 0 )
+      CHK( mpi_sub_mpi( &V1, &V1, N ) );
+
+    CHK( mpi_copy( X, &V1 ) );
+
+cleanup:
+
+    mpi_free( &V2, &V1, &TV, &TB, &G,
+              &U2, &U1, &TU, &TA, NULL );
+
+    return( ret );
+}
+
+#if !defined(NO_GENPRIME)
+static const int small_prime[] =
+{
+       3,  113,  271,  443,  619,  821,  1013,  1213,
+       5,  127,  277,  449,  631,  823,  1019,  1217,
+       7,  131,  281,  457,  641,  827,  1021,  1223,
+      11,  137,  283,  461,  643,  829,  1031,  1229,
+      13,  139,  293,  463,  647,  839,  1033,  1231,
+      17,  149,  307,  467,  653,  853,  1039,  1237,
+      19,  151,  311,  479,  659,  857,  1049,  1249,
+      23,  157,  313,  487,  661,  859,  1051,  1259,
+      29,  163,  317,  491,  673,  863,  1061,  1277,
+      31,  167,  331,  499,  677,  877,  1063,  1279,
+      37,  173,  337,  503,  683,  881,  1069,  1283,
+      41,  179,  347,  509,  691,  883,  1087,  1289,
+      43,  181,  349,  521,  701,  887,  1091,  1291,
+      47,  191,  353,  523,  709,  907,  1093,  1297,
+      53,  193,  359,  541,  719,  911,  1097,  1301,
+      59,  197,  367,  547,  727,  919,  1103,  1303,
+      61,  199,  373,  557,  733,  929,  1109,  1307,
+      67,  211,  379,  563,  739,  937,  1117,  1319,
+      71,  223,  383,  569,  743,  941,  1123,  1321,
+      73,  227,  389,  571,  751,  947,  1129,  1327,
+      79,  229,  397,  577,  757,  953,  1151,  1361,
+      83,  233,  401,  587,  761,  967,  1153,  1367,
+      89,  239,  409,  593,  769,  971,  1163,  1373,
+      97,  241,  419,  599,  773,  977,  1171,  1381,
+     101,  251,  421,  601,  787,  983,  1181,  1399,
+     103,  257,  431,  607,  797,  991,  1187,  1409,
+     107,  263,  433,  613,  809,  997,  1193,  1423,
+     109,  269,  439,  617,  811, 1009,  1201,  -110
+};
+
+/*
+ * Miller-Rabin primality test  (HAC 4.24)
+ */
+int mpi_is_prime( mpi *X )
+{
+    int ret, i, j, s, xs;
+    mpi W, R, T, A, RR;
+
+    if( mpi_cmp_int( X, 0 ) == 0 )
+        return( 0 );
+
+    mpi_init( &W, &R, &T, &A, &RR, NULL );
+    xs = X->s; X->s = 1;
+
+    /*
+     * test trivial factors first
+     */
+    if( ( X->p[0] & 1 ) == 0 )
+        return( ERR_MPI_IS_COMPOSITE );
+
+    for( i = 0; small_prime[i] > 0; i++ )
+    {
+        t_int r;
+
+        if( mpi_cmp_int( X, small_prime[i] ) <= 0 )
+            return( 0 );
+
+        CHK( mpi_mod_int( &r, X, small_prime[i] ) );
+
+        if( r == 0 )
+            return( ERR_MPI_IS_COMPOSITE );
+    }
+
+    /*
+     * W = |X| - 1
+     * R = W >> lsb( W )
+     */
+    CHK( mpi_sub_int( &W, X, 1 ) );
+    CHK( mpi_copy( &R, &W ) );
+    CHK( mpi_shift_r( &R, s = mpi_lsb( &W ) ) );
+
+    for( i = 0; i < 8; i++ )
+    {
+        /*
+         * pick a random A, 1 < A < |X| - 1
+         */
+        CHK( mpi_grow( &A, X->n ) );
+
+        for( j = 0; j < A.n; j++ )
+            A.p[j] = (t_int) rand() * rand();
+
+        CHK( mpi_shift_r( &A, mpi_size( &A ) -
+                              mpi_size( &W ) + 1 ) );
+        A.p[0] |= 3;
+
+        /*
+         * A = A^R mod |X|
+         */
+        CHK( mpi_exp_mod( &A, &A, &R, X, &RR ) );
+
+        if( mpi_cmp_mpi( &A, &W ) == 0 ||
+            mpi_cmp_int( &A,  1 ) == 0 )
+            continue;
+
+        j = 1;
+        while( j < s && mpi_cmp_mpi( &A, &W ) != 0 )
+        {
+            /*
+             * A = A * A mod |X|
+             */
+            CHK( mpi_mul_mpi( &T, &A, &A ) );
+            CHK( mpi_mod_mpi( &A, &T, X  ) );
+
+            if( mpi_cmp_int( &A, 1 ) == 0 )
+                break;
+
+            j++;
+        }
+
+        /*
+         * not prime if A != |X| - 1 or A == 1
+         */
+        if( mpi_cmp_mpi( &A, &W ) != 0 || j < s )
+        {
+            ret = ERR_MPI_IS_COMPOSITE;
+            break;
+        }
+    }
+
+cleanup:
+
+    X->s = xs;
+    mpi_free( &A, &T, &R, &W, NULL );
+    return( ret );
+}
+
+/*
+ * Prime number generation
+ */
+int mpi_gen_prime( mpi *X, int nbits, int dh_flag,
+                   int (*rng_f)(void *), void *rng_d )
+{
+    int ret, k, n;
+    unsigned char *p;
+    mpi Y;
+
+    if( nbits < 3 )
+        return( ERR_MPI_INVALID_PARAMETER );
+
+    mpi_init( &Y, NULL );
+
+    n = BITS_TO_LIMBS( nbits );
+
+    CHK( mpi_grow( X, n ) );
+    CHK( mpi_lset( X, 0 ) );
+
+    p = (unsigned char *) X->p;
+    for( k = 0; k < ciL * X->n; k++ )
+        *p++ = rng_f( rng_d );
+
+    k = mpi_size( X );
+    if( k < nbits ) CHK( mpi_shift_l( X, nbits - k ) );
+    if( k > nbits ) CHK( mpi_shift_r( X, k - nbits ) );
+    X->p[0] |= 3;
+
+    if( dh_flag == 0 )
+    {
+        while( ( ret = mpi_is_prime( X ) ) != 0 )
+        {
+            if( ret != ERR_MPI_IS_COMPOSITE )
+                goto cleanup;
+
+            CHK( mpi_add_int( X, X, 2 ) );
+        }
+    }
+    else
+    {
+        CHK( mpi_sub_int( &Y, X, 1 ) );
+        CHK( mpi_shift_r( &Y, 1 ) );
+
+        while( 1 )
+        {
+            if( ( ret = mpi_is_prime( X ) ) == 0 )
+            {
+                if( ( ret = mpi_is_prime( &Y ) ) == 0 )
+                    break;
+
+                if( ret != ERR_MPI_IS_COMPOSITE )
+                    goto cleanup;
+            }
+
+            if( ret != ERR_MPI_IS_COMPOSITE )
+                goto cleanup;
+
+            CHK( mpi_add_int( &Y, X, 1 ) );
+            CHK( mpi_add_int(  X, X, 2 ) );
+            CHK( mpi_shift_r( &Y, 1 ) );
+        }
+    }
+
+cleanup:
+
+    mpi_free( &Y, NULL );
+    return( ret );
+}
+#endif
+
+static const char _bignum_src[] = "_bignum_src";
+
+#ifdef SELF_TEST
+/*
+ * Checkup routine
+ */
+int mpi_self_test( void )
+{
+    int ret;
+    mpi A, E, N, X, Y, U, V;
+
+    mpi_init( &A, &E, &N, &X, &Y, &U, &V, NULL );
+
+    CHK( mpi_read( &A, "EFE021C2645FD1DC586E69184AF4A31E" \
+                       "D5F53E93B5F123FA41680867BA110131" \
+                       "944FE7952E2517337780CB0DB80E61AA" \
+                       "E7C8DDC6C5C6AADEB34EB38A2F40D5E6", 16 ) );
+    CHK( mpi_read( &E, "B2E7EFD37075B9F03FF989C7C5051C20" \
+                       "34D2A323810251127E7BF8625A4F49A5" \
+                       "F3E27F4DA8BD59C47D6DAABA4C8127BD" \
+                       "5B5C25763222FEFCCFC38B832366C29E", 16 ) );
+    CHK( mpi_read( &N, "0066A198186C18C10B2F5ED9B522752A" \
+                       "9830B69916E535C8F047518A889A43A5" \
+                       "94B6BED27A168D31D4A52F88925AA8F5", 16 ) );
+
+    CHK( mpi_mul_mpi( &X, &A, &N ) );
+    CHK( mpi_read( &U, "602AB7ECA597A3D6B56FF9829A5E8B85" \
+                       "9E857EA95A03512E2BAE7391688D264A" \
+                       "A5663B0341DB9CCFD2C4C5F421FEC814" \
+                       "8001B72E848A38CAE1C65F78E56ABDEF" \
+                       "E12D3C039B8A02D6BE593F0BBBDA56F1" \
+                       "ECF677152EF804370C1A305CAF3B5BF1" \
+                       "30879B56C61DE584A0F53A2447A51E", 16 ) );
+
+    printf( "  MPI test #1 (mul_mpi): " );
+    if( mpi_cmp_mpi( &X, &U ) != 0 )
+    {
+        printf( "failed\n" );
+        return( 1 );
+    }
+    printf( "passed\n" );
+
+    CHK( mpi_div_mpi( &X, &Y, &A, &N ) );
+    CHK( mpi_read( &U, "256567336059E52CAE22925474705F39A94", 16 ) );
+    CHK( mpi_read( &V, "6613F26162223DF488E9CD48CC132C7A" \
+                       "0AC93C701B001B092E4E5B9F73BCD27B" \
+                       "9EE50D0657C77F374E903CDFA4C642", 16 ) );
+
+    printf( "  MPI test #2 (div_mpi): " );
+    if( mpi_cmp_mpi( &X, &U ) != 0 ||
+        mpi_cmp_mpi( &Y, &V ) != 0 )
+    {
+        printf( "failed\n" );
+        return( 1 );
+    }
+    printf( "passed\n" );
+
+    CHK( mpi_exp_mod( &X, &A, &E, &N, NULL ) );
+    CHK( mpi_read( &U, "36E139AEA55215609D2816998ED020BB" \
+                       "BD96C37890F65171D948E9BC7CBAA4D9" \
+                       "325D24D6A3C12710F10A09FA08AB87", 16 ) );
+
+    printf( "  MPI test #3 (exp_mod): " );
+    if( mpi_cmp_mpi( &X, &U ) != 0 )
+    {
+        printf( "failed\n" );
+        return( 1 );
+    }
+    printf( "passed\n" );
+
+    CHK( mpi_inv_mod( &X, &A, &N ) );
+    CHK( mpi_read( &U, "003A0AAEDD7E784FC07D8F9EC6E3BFD5" \
+                       "C3DBA76456363A10869622EAC2DD84EC" \
+                       "C5B8A74DAC4D09E03B5E0BE779F2DF61", 16 ) );
+
+    printf( "  MPI test #4 (inv_mod): " );
+    if( mpi_cmp_mpi( &X, &U ) != 0 )
+    {
+        printf( "failed\n" );
+        return( 1 );
+    }
+    printf( "passed\n" );
+
+cleanup:
+
+    if( ret != 0 )
+        printf( "Unexpected error, return code = %d\n", ret );
+
+    mpi_free( &V, &U, &Y, &X, &N, &E, &A, NULL );
+
+    printf( "\n" );
+    return( 0 );
+}
+#else
+int mpi_self_test( void )
+{
+    return( 0 );
+}
+#endif
diff --git a/linux-bsp/asm-study/myboot/bootstrap.c b/linux-bsp/asm-study/myboot/bootstrap.c
new file mode 100644
index 0000000..66e8e29
--- /dev/null
+++ b/linux-bsp/asm-study/myboot/bootstrap.c
@@ -0,0 +1,122 @@
+/********************************************************************************************
+ *        File:  bootstrap.c
+ *     Version:  1.0.0
+ *   Copyright:  2011 (c) Guo Wenxue <guowenxue@gmail.com>
+ * Description:  This C code is the first stage bootloader(named bootstrap) 
+                 main code, test on FL2440 board.
+ *   ChangeLog:  1, Release initial version on "Tue Jul 12 16:43:18 CST 2011"
+ *
+ *******************************************************************************************/
+
+#include <common.h>
+#include <nand.h>
+
+int dbg_mode(struct boot_nand_t *nand);
+unsigned long do_go_exec (ulong (*entry)(int, char * const []), int argc, char * const argv[]);
+
+void print_buf(char *prompt, char *buf, int len)
+{
+    int i;
+    printf("%s %d bytes\n", prompt, len);
+    printf("------------------------------------------------------------------------------------\n");
+    for(i=0; i<len; i++) 
+    {
+        printf("0x%02x ", buf[i]); 
+        if(! (i+1)%32 )
+            printf("\n");
+    }
+
+    printf("\n");
+    printf("------------------------------------------------------------------------------------\n");
+}
+
+
+int bootstrap_main(void)
+{
+    struct boot_nand_t nand;
+    char    buf[0x20000];
+    ulong  test_block = 0x0;  /*0x1860000 is bad block*/
+//    char *addr = (char *)TEXT_BASE;
+    char *addr = (char *)0x36000000;
+
+    serial_init();
+    init_led_beep();
+
+    printf("\bBootstrap Version 0.0.1\n");
+
+    turn_led_on(LED0);
+
+    if (nand_init(&nand) < 0)
+    {
+        printf("Nandflash init failure.\n"); 
+        return -1;
+    }
+
+
+#if 0
+    nand_scrub(&nand);
+
+    nand_erase(&nand, test_block, 0x20000, SKIP_BAD_BLOCK);
+
+    memset(buf,0x00, sizeof(buf));
+    nand_read_spare(&nand, test_block, 64, buf);
+    print_buf("Spare area read:", buf, 64);
+
+    nand_read(&nand, test_block, nand.page_size, buf);
+    print_buf("Whole page Write:", buf, nand.page_size);
+#endif
+
+#if 0
+    /*Write spare area*/
+    memset(buf,0x44,sizeof(buf));
+
+    nand_write(&nand, test_block, nand.page_size, buf);
+    nand_read(&nand, test_block, nand.page_size, buf);
+    print_buf("Whole page Write:", buf, nand.page_size);
+
+
+    nand_write_spare(&nand, 0x0000, 64, buf);
+    nand_read_spare(&nand, test_block, 64, buf);
+    print_buf("Spare area read:", buf, 64);
+#endif
+
+    dbg_mode(&nand);
+
+    nand_read(&nand, LAUNCHER_NAND_ADDR, 1024, addr);
+    do_go_exec((void *)addr, 0, NULL);
+
+    while (1)
+        ;
+
+    return 0;
+}
+
+
+__attribute__((weak))
+unsigned long do_go_exec (ulong (*entry)(int, char * const []), int argc, char * const argv[])
+{
+     printf ("## Starting application at 0x%08lX ...\n", entry);
+     return entry (argc, argv);
+}
+
+int dbg_mode(struct boot_nand_t *nand)
+{
+    long size;
+    char *addr = (char *)TEXT_BASE;
+    ulong erase_size;
+
+    dbg_print("Comes into bootstrap debug mode and Xmodem wait for receive new launcher:\n");
+
+    beep(1);
+
+    size = xmodem_recv(addr);
+    dbg_print("\tBootstrap Receive Launcher file size: %ld bytes\n", size);
+
+    erase_size = (size/nand->block_size + 1)*nand->block_size;
+
+    nand_erase(nand, LAUNCHER_NAND_ADDR, erase_size, SKIP_BAD_BLOCK);
+    nand_write(nand, LAUNCHER_NAND_ADDR, size, addr);
+
+    return 0;
+}
+
diff --git a/linux-bsp/asm-study/myboot/bootstrap.lds b/linux-bsp/asm-study/myboot/bootstrap.lds
new file mode 100644
index 0000000..810e0a7
--- /dev/null
+++ b/linux-bsp/asm-study/myboot/bootstrap.lds
@@ -0,0 +1,32 @@
+/********************************************************************************************
+ *        File:  bootstrap.lds
+ *     Version:  1.0.0
+ *   Copyright:  2011 (c) Guo Wenxue <guowenxue@gmail.com>
+ * Description:  This is the LD linker configure script for bootstrap 
+ *   ChangeLog:  1, Release initial version on "Tue Jul 12 16:43:18 CST 2011"
+ *
+ *******************************************************************************************/
+
+OUTPUT_FORMAT("elf32-littlearm", "elf32-littlearm", "elf32-littlearm")
+OUTPUT_ARCH(arm)
+ENTRY(_start)
+
+SECTIONS{
+    . = ALIGN(4);
+    .text   :
+    {
+      start.o   (.text)
+      *(.text)
+    }
+    . = ALIGN(4);
+    .rodata : { *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*))) }
+    . = ALIGN(4);
+    .rodata : { *(.rodata) }
+    . = ALIGN(4);
+    .data : { *(.data) }
+    . = ALIGN(4);
+    __bss_start = .;
+    .bss : { *(.bss) }
+    _end = .;
+}
+
diff --git a/linux-bsp/asm-study/myboot/common.c b/linux-bsp/asm-study/myboot/common.c
new file mode 100644
index 0000000..01092f5
--- /dev/null
+++ b/linux-bsp/asm-study/myboot/common.c
@@ -0,0 +1,413 @@
+/*
+ *  linux/lib/vsprintf.c
+ *
+ *  Copyright (C) 1991, 1992  Linus Torvalds
+ */
+
+/* vsprintf.c -- Lars Wirzenius & Linus Torvalds. */
+/*
+ * Wirzenius wrote this portably, Torvalds fucked it up :-)
+ */
+
+#include <common.h>
+
+void * memset(void * s,int c,size_t count)
+{
+    unsigned long *sl = (unsigned long *) s;
+    unsigned long cl = 0;
+    char *s8;
+    int i;
+
+    /* do it one word at a time (32 bits or 64 bits) while possible */
+    if ( ((ulong)s & (sizeof(*sl) - 1)) == 0) {
+        for (i = 0; i < sizeof(*sl); i++) {
+            cl <<= 8;
+            cl |= c & 0xff;
+        }
+        while (count >= sizeof(*sl)) {
+            *sl++ = cl;
+            count -= sizeof(*sl);
+        }
+    } 
+    /* fill 8 bits at a time */
+    s8 = (char *)sl;
+    while (count--)
+        *s8++ = c;
+
+    return s;
+}
+
+#ifdef CONFIG_PRINTF_DBG
+
+size_t strnlen(const char *s, size_t count)
+{
+    const char *sc;
+
+    for (sc = s; count-- && *sc != '\0'; ++sc)
+        /* nothing */ ;
+    return sc - s;
+}
+
+#define is_digit(c)	((c) >= '0' && (c) <= '9')
+
+static int skip_atoi(const char **s)
+{
+    int i = 0;
+
+    while (is_digit(**s))
+        i = i * 10 + *((*s)++) - '0';
+    return i;
+}
+
+#define ZEROPAD	1               /* pad with zero */
+#define SIGN	2               /* unsigned/signed long */
+#define PLUS	4               /* show plus */
+#define SPACE	8               /* space if plus */
+#define LEFT	16              /* left justified */
+#define SPECIAL	32              /* 0x */
+#define LARGE	64              /* use 'ABCDEF' instead of 'abcdef' */
+
+#ifdef CFG_64BIT_VSPRINTF
+#define do_div(n,base) ({ \
+	unsigned int __res; \
+	__res = ((unsigned long long) n) % base; \
+	n = ((unsigned long long) n) / base; \
+	__res; \
+})
+#else
+#define do_div(n,base) ({ \
+	int __res; \
+	__res = ((unsigned long) n) % base; \
+	n = ((unsigned long) n) / base; \
+	__res; \
+})
+#endif
+
+#ifdef CFG_64BIT_VSPRINTF
+static char *number(char *str, long long num, unsigned int base, int size, int precision, int type)
+#else
+static char *number(char *str, long num, unsigned int base, int size, int precision, int type)
+#endif
+{
+    char c, sign, tmp[66];
+    const char *digits = "0123456789abcdefghijklmnopqrstuvwxyz";
+    int i;
+
+    if (type & LARGE)
+        digits = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
+    if (type & LEFT)
+        type &= ~ZEROPAD;
+    if (base < 2 || base > 36)
+        return 0;
+    c = (type & ZEROPAD) ? '0' : ' ';
+    sign = 0;
+    if (type & SIGN)
+    {
+        if (num < 0)
+        {
+            sign = '-';
+            num = -num;
+            size--;
+        }
+        else if (type & PLUS)
+        {
+            sign = '+';
+            size--;
+        }
+        else if (type & SPACE)
+        {
+            sign = ' ';
+            size--;
+        }
+    }
+    if (type & SPECIAL)
+    {
+        if (base == 16)
+            size -= 2;
+        else if (base == 8)
+            size--;
+    }
+    i = 0;
+    if (num == 0)
+        tmp[i++] = '0';
+    else
+        while (num != 0)
+            tmp[i++] = digits[do_div(num, base)];
+    if (i > precision)
+        precision = i;
+    size -= precision;
+    if (!(type & (ZEROPAD + LEFT)))
+        while (size-- > 0)
+            *str++ = ' ';
+    if (sign)
+        *str++ = sign;
+    if (type & SPECIAL)
+    {
+        if (base == 8)
+            *str++ = '0';
+        else if (base == 16)
+        {
+            *str++ = '0';
+            *str++ = digits[33];
+        }
+    }
+    if (!(type & LEFT))
+        while (size-- > 0)
+            *str++ = c;
+    while (i < precision--)
+        *str++ = '0';
+    while (i-- > 0)
+        *str++ = tmp[i];
+    while (size-- > 0)
+        *str++ = ' ';
+    return str;
+}
+
+/* Forward decl. needed for IP address printing stuff... */
+int sprintf(char *buf, const char *fmt, ...);
+
+int vsprintf(char *buf, const char *fmt, va_list args)
+{
+    int len;
+#ifdef CFG_64BIT_VSPRINTF
+    unsigned long long num;
+#else
+    unsigned long num;
+#endif
+    int i, base;
+    char *str;
+    const char *s;
+
+    int flags;                  /* flags to number() */
+
+    int field_width;            /* width of output field */
+    int precision;              /* min. # of digits for integers; max
+                                 * number of chars for from string */
+    int qualifier;              /* 'h', 'l', or 'q' for integer fields */
+
+    for (str = buf; *fmt; ++fmt)
+    {
+        if (*fmt != '%')
+        {
+            *str++ = *fmt;
+            continue;
+        }
+
+        /* process flags */
+        flags = 0;
+      repeat:
+        ++fmt;                  /* this also skips first '%' */
+        switch (*fmt)
+        {
+          case '-':
+              flags |= LEFT;
+              goto repeat;
+          case '+':
+              flags |= PLUS;
+              goto repeat;
+          case ' ':
+              flags |= SPACE;
+              goto repeat;
+          case '#':
+              flags |= SPECIAL;
+              goto repeat;
+          case '0':
+              flags |= ZEROPAD;
+              goto repeat;
+        }
+
+        /* get field width */
+        field_width = -1;
+        if (is_digit(*fmt))
+            field_width = skip_atoi(&fmt);
+        else if (*fmt == '*')
+        {
+            ++fmt;
+            /* it's the next argument */
+            field_width = va_arg(args, int);
+            if (field_width < 0)
+            {
+                field_width = -field_width;
+                flags |= LEFT;
+            }
+        }
+
+        /* get the precision */
+        precision = -1;
+        if (*fmt == '.')
+        {
+            ++fmt;
+            if (is_digit(*fmt))
+                precision = skip_atoi(&fmt);
+            else if (*fmt == '*')
+            {
+                ++fmt;
+                /* it's the next argument */
+                precision = va_arg(args, int);
+            }
+            if (precision < 0)
+                precision = 0;
+        }
+
+        /* get the conversion qualifier */
+        qualifier = -1;
+        if (*fmt == 'h' || *fmt == 'l' || *fmt == 'L' ||
+            *fmt == 'Z' || *fmt == 'z' || *fmt == 't' || *fmt == 'q')
+        {
+            qualifier = *fmt;
+            if (qualifier == 'l' && *(fmt + 1) == 'l')
+            {
+                qualifier = 'q';
+                ++fmt;
+            }
+            ++fmt;
+        }
+
+        /* default base */
+        base = 10;
+
+        switch (*fmt)
+        {
+          case 'c':
+              if (!(flags & LEFT))
+                  while (--field_width > 0)
+                      *str++ = ' ';
+              *str++ = (unsigned char)va_arg(args, int);
+              while (--field_width > 0)
+                  *str++ = ' ';
+              continue;
+
+          case 's':
+              s = va_arg(args, char *);
+              if (!s)
+                  s = "<NULL>";
+
+              len = strnlen(s, precision);
+
+              if (!(flags & LEFT))
+                  while (len < field_width--)
+                      *str++ = ' ';
+              for (i = 0; i < len; ++i)
+                  *str++ = *s++;
+              while (len < field_width--)
+                  *str++ = ' ';
+              continue;
+
+          case 'p':
+              if (field_width == -1)
+              {
+                  field_width = 2 * sizeof(void *);
+                  flags |= ZEROPAD;
+              }
+              str = number(str,
+                           (unsigned long)va_arg(args, void *), 16, field_width, precision, flags);
+              continue;
+
+          case 'n':
+              if (qualifier == 'l')
+              {
+                  long *ip = va_arg(args, long *);
+                  *ip = (str - buf);
+              }
+              else
+              {
+                  int *ip = va_arg(args, int *);
+                  *ip = (str - buf);
+              }
+              continue;
+
+          case '%':
+              *str++ = '%';
+              continue;
+
+              /* integer number formats - set up the flags and "break" */
+          case 'o':
+              base = 8;
+              break;
+
+          case 'X':
+              flags |= LARGE;
+          case 'x':
+              base = 16;
+              break;
+
+          case 'd':
+          case 'i':
+              flags |= SIGN;
+          case 'u':
+              break;
+
+          default:
+              *str++ = '%';
+              if (*fmt)
+                  *str++ = *fmt;
+              else
+                  --fmt;
+              continue;
+        }
+#ifdef CFG_64BIT_VSPRINTF
+        if (qualifier == 'q')   /* "quad" for 64 bit variables */
+            num = va_arg(args, unsigned long long);
+        else
+#endif
+        if (qualifier == 'l')
+        {
+            num = va_arg(args, unsigned long);
+        }
+        else if (qualifier == 'Z' || qualifier == 'z')
+        {
+            num = va_arg(args, size_t);
+        }
+        else if (qualifier == 't')
+        {
+            num = va_arg(args, ptrdiff_t);
+        }
+        else if (qualifier == 'h')
+        {
+            num = (unsigned short)va_arg(args, int);
+            if (flags & SIGN)
+                num = (short)num;
+        }
+        else if (flags & SIGN)
+            num = va_arg(args, int);
+        else
+            num = va_arg(args, unsigned int);
+        str = number(str, num, base, field_width, precision, flags);
+    }
+    *str = '\0';
+    return str - buf;
+}
+
+void printf(const char *fmt, ...)
+{
+    va_list args;
+    uint i;
+    char printbuffer[CFG_PBSIZE];
+
+    va_start(args, fmt);
+
+    /* For this to work, printbuffer must be larger than
+     * anything we ever want to print.
+     */
+    i = vsprintf(printbuffer, fmt, args);
+    va_end(args);
+
+    serial_puts(printbuffer);
+}
+
+int sprintf(char *buf, const char *fmt, ...)
+{
+    va_list args;
+    int i;
+
+    va_start(args, fmt);
+    i = vsprintf(buf, fmt, args);
+    va_end(args);
+    return i;
+}
+#else
+void printf(const char *fmt, ...)
+{
+
+}
+#endif                          /*Define CONFIG_PRINTF_DBG */
diff --git a/linux-bsp/asm-study/myboot/crc32.c b/linux-bsp/asm-study/myboot/crc32.c
new file mode 100644
index 0000000..b87391e
--- /dev/null
+++ b/linux-bsp/asm-study/myboot/crc32.c
@@ -0,0 +1,218 @@
+/*
+ * This file is derived from crc32.c from the zlib-1.1.3 distribution
+ * by Jean-loup Gailly and Mark Adler.
+ */
+
+/* crc32.c -- compute the CRC-32 of a data stream
+ * Copyright (C) 1995-1998 Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+#include <common.h>
+
+#define __cpu_to_le32(x) ((__u32)(x))
+#define cpu_to_le32 __cpu_to_le32
+# define le32_to_cpu(x)     (x)
+
+#define local static
+#define ZEXPORT	/* empty */
+
+#define tole(x) cpu_to_le32(x)
+
+#ifdef DYNAMIC_CRC_TABLE
+
+local int crc_table_empty = 1;
+local uint32_t crc_table[256];
+local void make_crc_table OF((void));
+
+/*
+  Generate a table for a byte-wise 32-bit CRC calculation on the polynomial:
+  x^32+x^26+x^23+x^22+x^16+x^12+x^11+x^10+x^8+x^7+x^5+x^4+x^2+x+1.
+
+  Polynomials over GF(2) are represented in binary, one bit per coefficient,
+  with the lowest powers in the most significant bit.  Then adding polynomials
+  is just exclusive-or, and multiplying a polynomial by x is a right shift by
+  one.  If we call the above polynomial p, and represent a byte as the
+  polynomial q, also with the lowest power in the most significant bit (so the
+  byte 0xb1 is the polynomial x^7+x^3+x+1), then the CRC is (q*x^32) mod p,
+  where a mod b means the remainder after dividing a by b.
+
+  This calculation is done using the shift-register method of multiplying and
+  taking the remainder.  The register is initialized to zero, and for each
+  incoming bit, x^32 is added mod p to the register if the bit is a one (where
+  x^32 mod p is p+x^32 = x^26+...+1), and the register is multiplied mod p by
+  x (which is shifting right by one and adding x^32 mod p if the bit shifted
+  out is a one).  We start with the highest power (least significant bit) of
+  q and repeat for all eight bits of q.
+
+  The table is simply the CRC of all possible eight bit values.  This is all
+  the information needed to generate CRC's on data a byte at a time for all
+  combinations of CRC register values and incoming bytes.
+*/
+local void make_crc_table()
+{
+  uint32_t c;
+  int n, k;
+  uLong poly;		/* polynomial exclusive-or pattern */
+  /* terms of polynomial defining this crc (except x^32): */
+  static const Byte p[] = {0,1,2,4,5,7,8,10,11,12,16,22,23,26};
+
+  /* make exclusive-or pattern from polynomial (0xedb88320L) */
+  poly = 0L;
+  for (n = 0; n < sizeof(p)/sizeof(Byte); n++)
+    poly |= 1L << (31 - p[n]);
+
+  for (n = 0; n < 256; n++)
+  {
+    c = (uLong)n;
+    for (k = 0; k < 8; k++)
+      c = c & 1 ? poly ^ (c >> 1) : c >> 1;
+    crc_table[n] = tole(c);
+  }
+  crc_table_empty = 0;
+}
+#else
+/* ========================================================================
+ * Table of CRC-32's of all single-byte values (made by make_crc_table)
+ */
+
+local const uint32_t crc_table[256] = {
+tole(0x00000000L), tole(0x77073096L), tole(0xee0e612cL), tole(0x990951baL),
+tole(0x076dc419L), tole(0x706af48fL), tole(0xe963a535L), tole(0x9e6495a3L),
+tole(0x0edb8832L), tole(0x79dcb8a4L), tole(0xe0d5e91eL), tole(0x97d2d988L),
+tole(0x09b64c2bL), tole(0x7eb17cbdL), tole(0xe7b82d07L), tole(0x90bf1d91L),
+tole(0x1db71064L), tole(0x6ab020f2L), tole(0xf3b97148L), tole(0x84be41deL),
+tole(0x1adad47dL), tole(0x6ddde4ebL), tole(0xf4d4b551L), tole(0x83d385c7L),
+tole(0x136c9856L), tole(0x646ba8c0L), tole(0xfd62f97aL), tole(0x8a65c9ecL),
+tole(0x14015c4fL), tole(0x63066cd9L), tole(0xfa0f3d63L), tole(0x8d080df5L),
+tole(0x3b6e20c8L), tole(0x4c69105eL), tole(0xd56041e4L), tole(0xa2677172L),
+tole(0x3c03e4d1L), tole(0x4b04d447L), tole(0xd20d85fdL), tole(0xa50ab56bL),
+tole(0x35b5a8faL), tole(0x42b2986cL), tole(0xdbbbc9d6L), tole(0xacbcf940L),
+tole(0x32d86ce3L), tole(0x45df5c75L), tole(0xdcd60dcfL), tole(0xabd13d59L),
+tole(0x26d930acL), tole(0x51de003aL), tole(0xc8d75180L), tole(0xbfd06116L),
+tole(0x21b4f4b5L), tole(0x56b3c423L), tole(0xcfba9599L), tole(0xb8bda50fL),
+tole(0x2802b89eL), tole(0x5f058808L), tole(0xc60cd9b2L), tole(0xb10be924L),
+tole(0x2f6f7c87L), tole(0x58684c11L), tole(0xc1611dabL), tole(0xb6662d3dL),
+tole(0x76dc4190L), tole(0x01db7106L), tole(0x98d220bcL), tole(0xefd5102aL),
+tole(0x71b18589L), tole(0x06b6b51fL), tole(0x9fbfe4a5L), tole(0xe8b8d433L),
+tole(0x7807c9a2L), tole(0x0f00f934L), tole(0x9609a88eL), tole(0xe10e9818L),
+tole(0x7f6a0dbbL), tole(0x086d3d2dL), tole(0x91646c97L), tole(0xe6635c01L),
+tole(0x6b6b51f4L), tole(0x1c6c6162L), tole(0x856530d8L), tole(0xf262004eL),
+tole(0x6c0695edL), tole(0x1b01a57bL), tole(0x8208f4c1L), tole(0xf50fc457L),
+tole(0x65b0d9c6L), tole(0x12b7e950L), tole(0x8bbeb8eaL), tole(0xfcb9887cL),
+tole(0x62dd1ddfL), tole(0x15da2d49L), tole(0x8cd37cf3L), tole(0xfbd44c65L),
+tole(0x4db26158L), tole(0x3ab551ceL), tole(0xa3bc0074L), tole(0xd4bb30e2L),
+tole(0x4adfa541L), tole(0x3dd895d7L), tole(0xa4d1c46dL), tole(0xd3d6f4fbL),
+tole(0x4369e96aL), tole(0x346ed9fcL), tole(0xad678846L), tole(0xda60b8d0L),
+tole(0x44042d73L), tole(0x33031de5L), tole(0xaa0a4c5fL), tole(0xdd0d7cc9L),
+tole(0x5005713cL), tole(0x270241aaL), tole(0xbe0b1010L), tole(0xc90c2086L),
+tole(0x5768b525L), tole(0x206f85b3L), tole(0xb966d409L), tole(0xce61e49fL),
+tole(0x5edef90eL), tole(0x29d9c998L), tole(0xb0d09822L), tole(0xc7d7a8b4L),
+tole(0x59b33d17L), tole(0x2eb40d81L), tole(0xb7bd5c3bL), tole(0xc0ba6cadL),
+tole(0xedb88320L), tole(0x9abfb3b6L), tole(0x03b6e20cL), tole(0x74b1d29aL),
+tole(0xead54739L), tole(0x9dd277afL), tole(0x04db2615L), tole(0x73dc1683L),
+tole(0xe3630b12L), tole(0x94643b84L), tole(0x0d6d6a3eL), tole(0x7a6a5aa8L),
+tole(0xe40ecf0bL), tole(0x9309ff9dL), tole(0x0a00ae27L), tole(0x7d079eb1L),
+tole(0xf00f9344L), tole(0x8708a3d2L), tole(0x1e01f268L), tole(0x6906c2feL),
+tole(0xf762575dL), tole(0x806567cbL), tole(0x196c3671L), tole(0x6e6b06e7L),
+tole(0xfed41b76L), tole(0x89d32be0L), tole(0x10da7a5aL), tole(0x67dd4accL),
+tole(0xf9b9df6fL), tole(0x8ebeeff9L), tole(0x17b7be43L), tole(0x60b08ed5L),
+tole(0xd6d6a3e8L), tole(0xa1d1937eL), tole(0x38d8c2c4L), tole(0x4fdff252L),
+tole(0xd1bb67f1L), tole(0xa6bc5767L), tole(0x3fb506ddL), tole(0x48b2364bL),
+tole(0xd80d2bdaL), tole(0xaf0a1b4cL), tole(0x36034af6L), tole(0x41047a60L),
+tole(0xdf60efc3L), tole(0xa867df55L), tole(0x316e8eefL), tole(0x4669be79L),
+tole(0xcb61b38cL), tole(0xbc66831aL), tole(0x256fd2a0L), tole(0x5268e236L),
+tole(0xcc0c7795L), tole(0xbb0b4703L), tole(0x220216b9L), tole(0x5505262fL),
+tole(0xc5ba3bbeL), tole(0xb2bd0b28L), tole(0x2bb45a92L), tole(0x5cb36a04L),
+tole(0xc2d7ffa7L), tole(0xb5d0cf31L), tole(0x2cd99e8bL), tole(0x5bdeae1dL),
+tole(0x9b64c2b0L), tole(0xec63f226L), tole(0x756aa39cL), tole(0x026d930aL),
+tole(0x9c0906a9L), tole(0xeb0e363fL), tole(0x72076785L), tole(0x05005713L),
+tole(0x95bf4a82L), tole(0xe2b87a14L), tole(0x7bb12baeL), tole(0x0cb61b38L),
+tole(0x92d28e9bL), tole(0xe5d5be0dL), tole(0x7cdcefb7L), tole(0x0bdbdf21L),
+tole(0x86d3d2d4L), tole(0xf1d4e242L), tole(0x68ddb3f8L), tole(0x1fda836eL),
+tole(0x81be16cdL), tole(0xf6b9265bL), tole(0x6fb077e1L), tole(0x18b74777L),
+tole(0x88085ae6L), tole(0xff0f6a70L), tole(0x66063bcaL), tole(0x11010b5cL),
+tole(0x8f659effL), tole(0xf862ae69L), tole(0x616bffd3L), tole(0x166ccf45L),
+tole(0xa00ae278L), tole(0xd70dd2eeL), tole(0x4e048354L), tole(0x3903b3c2L),
+tole(0xa7672661L), tole(0xd06016f7L), tole(0x4969474dL), tole(0x3e6e77dbL),
+tole(0xaed16a4aL), tole(0xd9d65adcL), tole(0x40df0b66L), tole(0x37d83bf0L),
+tole(0xa9bcae53L), tole(0xdebb9ec5L), tole(0x47b2cf7fL), tole(0x30b5ffe9L),
+tole(0xbdbdf21cL), tole(0xcabac28aL), tole(0x53b39330L), tole(0x24b4a3a6L),
+tole(0xbad03605L), tole(0xcdd70693L), tole(0x54de5729L), tole(0x23d967bfL),
+tole(0xb3667a2eL), tole(0xc4614ab8L), tole(0x5d681b02L), tole(0x2a6f2b94L),
+tole(0xb40bbe37L), tole(0xc30c8ea1L), tole(0x5a05df1bL), tole(0x2d02ef8dL)
+};
+#endif
+
+#if 0
+/* =========================================================================
+ * This function can be used by asm versions of crc32()
+ */
+const uint32_t * ZEXPORT get_crc_table()
+{
+#ifdef DYNAMIC_CRC_TABLE
+  if (crc_table_empty) make_crc_table();
+#endif
+  return (const uint32_t *)crc_table;
+}
+#endif
+
+/* ========================================================================= */
+# if __BYTE_ORDER == __LITTLE_ENDIAN
+#  define DO_CRC(x) crc = tab[(crc ^ (x)) & 255] ^ (crc >> 8)
+# else
+#  define DO_CRC(x) crc = tab[((crc >> 24) ^ (x)) & 255] ^ (crc << 8)
+# endif
+
+/* ========================================================================= */
+
+/* No ones complement version. JFFS2 (and other things ?)
+ * don't use ones compliment in their CRC calculations.
+ */
+uint32_t ZEXPORT crc32_no_comp(uint32_t crc, const uchar *buf, uint len)
+{
+    const uint32_t *tab = crc_table;
+    const uint32_t *b =(const uint32_t *)buf;
+    size_t rem_len;
+#ifdef DYNAMIC_CRC_TABLE
+    if (crc_table_empty)
+      make_crc_table();
+#endif
+    crc = cpu_to_le32(crc);
+    /* Align it */
+    if (((long)b) & 3 && len) {
+	 uint8_t *p = (uint8_t *)b;
+	 do {
+	      DO_CRC(*p++);
+	 } while ((--len) && ((long)p)&3);
+	 b = (uint32_t *)p;
+    }
+
+    rem_len = len & 3;
+    len = len >> 2;
+    for (--b; len; --len) {
+	 /* load data 32 bits wide, xor data 32 bits wide. */
+	 crc ^= *++b; /* use pre increment for speed */
+	 DO_CRC(0);
+	 DO_CRC(0);
+	 DO_CRC(0);
+	 DO_CRC(0);
+    }
+    len = rem_len;
+    /* And the last few bytes */
+    if (len) {
+	 uint8_t *p = (uint8_t *)(b + 1) - 1;
+	 do {
+	      DO_CRC(*++p); /* use pre increment for speed */
+	 } while (--len);
+    }
+
+    return le32_to_cpu(crc);
+}
+#undef DO_CRC
+
+uint32_t ZEXPORT crc32 (uint32_t crc, const uchar *p, uint len)
+{
+     return crc32_no_comp(crc ^ 0xffffffffL, p, len) ^ 0xffffffffL;
+}
+
diff --git a/linux-bsp/asm-study/myboot/include/asm/errno.h b/linux-bsp/asm-study/myboot/include/asm/errno.h
new file mode 100644
index 0000000..f9cc47b
--- /dev/null
+++ b/linux-bsp/asm-study/myboot/include/asm/errno.h
@@ -0,0 +1,138 @@
+#ifndef _ARM_ERRNO_H
+#define _ARM_ERRNO_H
+
+#define	EPERM		 1          /* Operation not permitted */
+#define	ENOENT		 2          /* No such file or directory */
+#define	ESRCH		 3          /* No such process */
+#define	EINTR		 4          /* Interrupted system call */
+#define	EIO		 5              /* I/O error */
+#define	ENXIO		 6          /* No such device or address */
+#define	E2BIG		 7          /* Arg list too long */
+#define	ENOEXEC		 8          /* Exec format error */
+#define	EBADF		 9          /* Bad file number */
+#define	ECHILD		10          /* No child processes */
+#define	EAGAIN		11          /* Try again */
+#define	ENOMEM		12          /* Out of memory */
+#define	EACCES		13          /* Permission denied */
+#define	EFAULT		14          /* Bad address */
+#define	ENOTBLK		15          /* Block device required */
+#define	EBUSY		16          /* Device or resource busy */
+#define	EEXIST		17          /* File exists */
+#define	EXDEV		18          /* Cross-device link */
+#define	ENODEV		19          /* No such device */
+#define	ENOTDIR		20          /* Not a directory */
+#define	EISDIR		21          /* Is a directory */
+#define	EINVAL		22          /* Invalid argument */
+#define	ENFILE		23          /* File table overflow */
+#define	EMFILE		24          /* Too many open files */
+#define	ENOTTY		25          /* Not a typewriter */
+#define	ETXTBSY		26          /* Text file busy */
+#define	EFBIG		27          /* File too large */
+#define	ENOSPC		28          /* No space left on device */
+#define	ESPIPE		29          /* Illegal seek */
+#define	EROFS		30          /* Read-only file system */
+#define	EMLINK		31          /* Too many links */
+#define	EPIPE		32          /* Broken pipe */
+#define	EDOM		33          /* Math argument out of domain of func */
+#define	ERANGE		34          /* Math result not representable */
+#define	EDEADLK		35          /* Resource deadlock would occur */
+#define	ENAMETOOLONG	36      /* File name too long */
+#define	ENOLCK		37          /* No record locks available */
+#define	ENOSYS		38          /* Function not implemented */
+#define	ENOTEMPTY	39          /* Directory not empty */
+#define	ELOOP		40          /* Too many symbolic links encountered */
+#define	EWOULDBLOCK	EAGAIN      /* Operation would block */
+#define	ENOMSG		42          /* No message of desired type */
+#define	EIDRM		43          /* Identifier removed */
+#define	ECHRNG		44          /* Channel number out of range */
+#define	EL2NSYNC	45          /* Level 2 not synchronized */
+#define	EL3HLT		46          /* Level 3 halted */
+#define	EL3RST		47          /* Level 3 reset */
+#define	ELNRNG		48          /* Link number out of range */
+#define	EUNATCH		49          /* Protocol driver not attached */
+#define	ENOCSI		50          /* No CSI structure available */
+#define	EL2HLT		51          /* Level 2 halted */
+#define	EBADE		52          /* Invalid exchange */
+#define	EBADR		53          /* Invalid request descriptor */
+#define	EXFULL		54          /* Exchange full */
+#define	ENOANO		55          /* No anode */
+#define	EBADRQC		56          /* Invalid request code */
+#define	EBADSLT		57          /* Invalid slot */
+#define	EDEADLOCK	58          /* File locking deadlock error */
+#define	EBFONT		59          /* Bad font file format */
+#define	ENOSTR		60          /* Device not a stream */
+#define	ENODATA		61          /* No data available */
+#define	ETIME		62          /* Timer expired */
+#define	ENOSR		63          /* Out of streams resources */
+#define	ENONET		64          /* Machine is not on the network */
+#define	ENOPKG		65          /* Package not installed */
+#define	EREMOTE		66          /* Object is remote */
+#define	ENOLINK		67          /* Link has been severed */
+#define	EADV		68          /* Advertise error */
+#define	ESRMNT		69          /* Srmount error */
+#define	ECOMM		70          /* Communication error on send */
+#define	EPROTO		71          /* Protocol error */
+#define	EMULTIHOP	72          /* Multihop attempted */
+#define	EDOTDOT		73          /* RFS specific error */
+#define	EBADMSG		74          /* Not a data message */
+#define	EOVERFLOW	75          /* Value too large for defined data type */
+#define	ENOTUNIQ	76          /* Name not unique on network */
+#define	EBADFD		77          /* File descriptor in bad state */
+#define	EREMCHG		78          /* Remote address changed */
+#define	ELIBACC		79          /* Can not access a needed shared library */
+#define	ELIBBAD		80          /* Accessing a corrupted shared library */
+#define	ELIBSCN		81          /* .lib section in a.out corrupted */
+#define	ELIBMAX		82          /* Attempting to link in too many shared libraries */
+#define	ELIBEXEC	83          /* Cannot exec a shared library directly */
+#define	EILSEQ		84          /* Illegal byte sequence */
+#define	ERESTART	85          /* Interrupted system call should be restarted */
+#define	ESTRPIPE	86          /* Streams pipe error */
+#define	EUSERS		87          /* Too many users */
+#define	ENOTSOCK	88          /* Socket operation on non-socket */
+#define	EDESTADDRREQ	89      /* Destination address required */
+#define	EMSGSIZE	90          /* Message too long */
+#define	EPROTOTYPE	91          /* Protocol wrong type for socket */
+#define	ENOPROTOOPT	92          /* Protocol not available */
+#define	EPROTONOSUPPORT	93      /* Protocol not supported */
+#define	ESOCKTNOSUPPORT	94      /* Socket type not supported */
+#define	EOPNOTSUPP	95          /* Operation not supported on transport endpoint */
+#define	EPFNOSUPPORT	96      /* Protocol family not supported */
+#define	EAFNOSUPPORT	97      /* Address family not supported by protocol */
+#define	EADDRINUSE	98          /* Address already in use */
+#define	EADDRNOTAVAIL	99      /* Cannot assign requested address */
+#define	ENETDOWN	100         /* Network is down */
+#define	ENETUNREACH	101         /* Network is unreachable */
+#define	ENETRESET	102         /* Network dropped connection because of reset */
+#define	ECONNABORTED	103     /* Software caused connection abort */
+#define	ECONNRESET	104         /* Connection reset by peer */
+#define	ENOBUFS		105         /* No buffer space available */
+#define	EISCONN		106         /* Transport endpoint is already connected */
+#define	ENOTCONN	107         /* Transport endpoint is not connected */
+#define	ESHUTDOWN	108         /* Cannot send after transport endpoint shutdown */
+#define	ETOOMANYREFS	109     /* Too many references: cannot splice */
+#define	ETIMEDOUT	110         /* Connection timed out */
+#define	ECONNREFUSED	111     /* Connection refused */
+#define	EHOSTDOWN	112         /* Host is down */
+#define	EHOSTUNREACH	113     /* No route to host */
+#define	EALREADY	114         /* Operation already in progress */
+#define	EINPROGRESS	115         /* Operation now in progress */
+#define	ESTALE		116         /* Stale NFS file handle */
+#define	EUCLEAN		117         /* Structure needs cleaning */
+#define	ENOTNAM		118         /* Not a XENIX named type file */
+#define	ENAVAIL		119         /* No XENIX semaphores available */
+#define	EISNAM		120         /* Is a named type file */
+#define	EREMOTEIO	121         /* Remote I/O error */
+#define	EDQUOT		122         /* Quota exceeded */
+
+#define	ENOMEDIUM	123         /* No medium found */
+#define	EMEDIUMTYPE	124         /* Wrong medium type */
+
+/* Should never be seen by user programs */
+#define ERESTARTSYS	512
+#define ERESTARTNOINTR	513
+#define ERESTARTNOHAND	514     /* restart if no handler.. */
+#define ENOIOCTLCMD	515         /* No ioctl command */
+
+#define _LAST_ERRNO	515
+
+#endif
diff --git a/linux-bsp/asm-study/myboot/include/asm/hardware.h b/linux-bsp/asm-study/myboot/include/asm/hardware.h
new file mode 100644
index 0000000..a6e20ad
--- /dev/null
+++ b/linux-bsp/asm-study/myboot/include/asm/hardware.h
@@ -0,0 +1,43 @@
+#ifndef _ARCH_HARDWARE_H_
+#define _ARCH_HARDWARE_H_
+
+#include <asm/sizes.h>
+
+#ifndef __ASSEMBLY__
+#define UData(Data)	((unsigned long) (Data))
+
+#define __REG(x)	(*(vu_long *)(x))
+#define __REGl(x)	(*(vu_long *)(x))
+#define __REGi(x)   (*(vu_int *)(x))
+#define __REGw(x)	(*(vu_short *)(x))
+#define __REGb(x)	(*(vu_char *)(x))
+#define __REG2(x,y)	(*(vu_long *)((x) + (y)))
+#else
+#define UData(Data)	(Data)
+
+#define __REG(x)	(x)
+#define __REGl(x)	(x)
+#define __REGi(x)	(x)
+#define __REGw(x)	(x)
+#define __REGb(x)	(x)
+#define __REG2(x,y)	((x) + (y))
+#endif
+
+#define Fld(Size, Shft)	(((Size) << 16) + (Shft))
+
+#define FSize(Field)	((Field) >> 16)
+#define FShft(Field)	((Field) & 0x0000FFFF)
+#define FMsk(Field)	(((UData (1) << FSize (Field)) - 1) << FShft (Field))
+#define FAlnMsk(Field)	((UData (1) << FSize (Field)) - 1)
+#define F1stBit(Field)	(UData (1) << FShft (Field))
+
+#define FClrBit(Data, Bit)	(Data = (Data & ~(Bit)))
+#define FClrFld(Data, Field)	(Data = (Data & ~FMsk(Field)))
+
+#define FInsrt(Value, Field) \
+                	(UData (Value) << FShft (Field))
+
+#define FExtr(Data, Field) \
+                	((UData (Data) >> FShft (Field)) & FAlnMsk (Field))
+
+#endif                          /* _ARCH_HARDWARE_H_ */
diff --git a/linux-bsp/asm-study/myboot/include/asm/io.h b/linux-bsp/asm-study/myboot/include/asm/io.h
new file mode 100644
index 0000000..8e5f5fd
--- /dev/null
+++ b/linux-bsp/asm-study/myboot/include/asm/io.h
@@ -0,0 +1,330 @@
+/*
+ *  linux/include/asm-arm/io.h
+ *
+ *  Copyright (C) 1996-2000 Russell King
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Modifications:
+ *  16-Sep-1996	RMK	Inlined the inx/outx functions & optimised for both
+ *			constant addresses and variable addresses.
+ *  04-Dec-1997	RMK	Moved a lot of this stuff to the new architecture
+ *			specific IO header files.
+ *  27-Mar-1999	PJB	Second parameter of memcpy_toio is const..
+ *  04-Apr-1999	PJB	Added check_signature.
+ *  12-Dec-1999	RMK	More cleanups
+ *  18-Jun-2000 RMK	Removed virt_to_* and friends definitions
+ */
+#ifndef __ASM_ARM_IO_H
+#define __ASM_ARM_IO_H
+
+#ifdef __KERNEL__
+
+#include <linux/types.h>
+
+static inline void sync(void)
+{
+}
+
+/*
+ * Given a physical address and a length, return a virtual address
+ * that can be used to access the memory range with the caching
+ * properties specified by "flags".
+ */
+#define MAP_NOCACHE	(0)
+#define MAP_WRCOMBINE	(0)
+#define MAP_WRBACK	(0)
+#define MAP_WRTHROUGH	(0)
+
+static inline void *map_physmem(phys_addr_t paddr, unsigned long len, unsigned long flags)
+{
+    return (void *)paddr;
+}
+
+/*
+ * Take down a mapping set up by map_physmem().
+ */
+static inline void unmap_physmem(void *vaddr, unsigned long flags)
+{
+
+}
+
+/*
+ * Generic virtual read/write.  Note that we don't support half-word
+ * read/writes.  We define __arch_*[bl] here, and leave __arch_*w
+ * to the architecture specific code.
+ */
+#define __arch_getb(a)			(*(volatile unsigned char *)(a))
+#define __arch_getw(a)			(*(volatile unsigned short *)(a))
+#define __arch_getl(a)			(*(volatile unsigned int *)(a))
+
+#define __arch_putb(v,a)		(*(volatile unsigned char *)(a) = (v))
+#define __arch_putw(v,a)		(*(volatile unsigned short *)(a) = (v))
+#define __arch_putl(v,a)		(*(volatile unsigned int *)(a) = (v))
+
+extern void __raw_writesb(unsigned int addr, const void *data, int bytelen);
+extern void __raw_writesw(unsigned int addr, const void *data, int wordlen);
+extern void __raw_writesl(unsigned int addr, const void *data, int longlen);
+
+extern void __raw_readsb(unsigned int addr, void *data, int bytelen);
+extern void __raw_readsw(unsigned int addr, void *data, int wordlen);
+extern void __raw_readsl(unsigned int addr, void *data, int longlen);
+
+#define __raw_writeb(v,a)		__arch_putb(v,a)
+#define __raw_writew(v,a)		__arch_putw(v,a)
+#define __raw_writel(v,a)		__arch_putl(v,a)
+
+#define __raw_readb(a)			__arch_getb(a)
+#define __raw_readw(a)			__arch_getw(a)
+#define __raw_readl(a)			__arch_getl(a)
+
+#define writeb(v,a)			__arch_putb(v,a)
+#define writew(v,a)			__arch_putw(v,a)
+#define writel(v,a)			__arch_putl(v,a)
+
+#define readb(a)			__arch_getb(a)
+#define readw(a)			__arch_getw(a)
+#define readl(a)			__arch_getl(a)
+
+/*
+ * The compiler seems to be incapable of optimising constants
+ * properly.  Spell it out to the compiler in some cases.
+ * These are only valid for small values of "off" (< 1<<12)
+ */
+#define __raw_base_writeb(val,base,off)	__arch_base_putb(val,base,off)
+#define __raw_base_writew(val,base,off)	__arch_base_putw(val,base,off)
+#define __raw_base_writel(val,base,off)	__arch_base_putl(val,base,off)
+
+#define __raw_base_readb(base,off)	__arch_base_getb(base,off)
+#define __raw_base_readw(base,off)	__arch_base_getw(base,off)
+#define __raw_base_readl(base,off)	__arch_base_getl(base,off)
+
+/*
+ * Now, pick up the machine-defined IO definitions
+ */
+#if 0                           /* XXX###XXX */
+#include <asm/arch/io.h>
+#endif                          /* XXX###XXX */
+
+/*
+ *  IO port access primitives
+ *  -------------------------
+ *
+ * The ARM doesn't have special IO access instructions; all IO is memory
+ * mapped.  Note that these are defined to perform little endian accesses
+ * only.  Their primary purpose is to access PCI and ISA peripherals.
+ *
+ * Note that for a big endian machine, this implies that the following
+ * big endian mode connectivity is in place, as described by numerous
+ * ARM documents:
+ *
+ *    PCI:  D0-D7   D8-D15 D16-D23 D24-D31
+ *    ARM: D24-D31 D16-D23  D8-D15  D0-D7
+ *
+ * The machine specific io.h include defines __io to translate an "IO"
+ * address to a memory address.
+ *
+ * Note that we prevent GCC re-ordering or caching values in expressions
+ * by introducing sequence points into the in*() definitions.  Note that
+ * __raw_* do not guarantee this behaviour.
+ *
+ * The {in,out}[bwl] macros are for emulating x86-style PCI/ISA IO space.
+ */
+#ifdef __io
+#define outb(v,p)			__raw_writeb(v,__io(p))
+#define outw(v,p)			__raw_writew(cpu_to_le16(v),__io(p))
+#define outl(v,p)			__raw_writel(cpu_to_le32(v),__io(p))
+
+#define inb(p)	({ unsigned int __v = __raw_readb(__io(p)); __v; })
+#define inw(p)	({ unsigned int __v = le16_to_cpu(__raw_readw(__io(p))); __v; })
+#define inl(p)	({ unsigned int __v = le32_to_cpu(__raw_readl(__io(p))); __v; })
+
+#define outsb(p,d,l)			__raw_writesb(__io(p),d,l)
+#define outsw(p,d,l)			__raw_writesw(__io(p),d,l)
+#define outsl(p,d,l)			__raw_writesl(__io(p),d,l)
+
+#define insb(p,d,l)			__raw_readsb(__io(p),d,l)
+#define insw(p,d,l)			__raw_readsw(__io(p),d,l)
+#define insl(p,d,l)			__raw_readsl(__io(p),d,l)
+#endif
+
+#define outb_p(val,port)		outb((val),(port))
+#define outw_p(val,port)		outw((val),(port))
+#define outl_p(val,port)		outl((val),(port))
+#define inb_p(port)			inb((port))
+#define inw_p(port)			inw((port))
+#define inl_p(port)			inl((port))
+
+#define outsb_p(port,from,len)		outsb(port,from,len)
+#define outsw_p(port,from,len)		outsw(port,from,len)
+#define outsl_p(port,from,len)		outsl(port,from,len)
+#define insb_p(port,to,len)		insb(port,to,len)
+#define insw_p(port,to,len)		insw(port,to,len)
+#define insl_p(port,to,len)		insl(port,to,len)
+
+/*
+ * ioremap and friends.
+ *
+ * ioremap takes a PCI memory address, as specified in
+ * linux/Documentation/IO-mapping.txt.  If you want a
+ * physical address, use __ioremap instead.
+ */
+extern void *__ioremap(unsigned long offset, size_t size, unsigned long flags);
+extern void __iounmap(void *addr);
+
+/*
+ * Generic ioremap support.
+ *
+ * Define:
+ *  iomem_valid_addr(off,size)
+ *  iomem_to_phys(off)
+ */
+#ifdef iomem_valid_addr
+#define __arch_ioremap(off,sz,nocache)				\
+ ({								\
+	unsigned long _off = (off), _size = (sz);		\
+	void *_ret = (void *)0;					\
+	if (iomem_valid_addr(_off, _size))			\
+		_ret = __ioremap(iomem_to_phys(_off),_size,0);	\
+	_ret;							\
+ })
+
+#define __arch_iounmap __iounmap
+#endif
+
+#define ioremap(off,sz)			__arch_ioremap((off),(sz),0)
+#define ioremap_nocache(off,sz)		__arch_ioremap((off),(sz),1)
+#define iounmap(_addr)			__arch_iounmap(_addr)
+
+/*
+ * DMA-consistent mapping functions.  These allocate/free a region of
+ * uncached, unwrite-buffered mapped memory space for use with DMA
+ * devices.  This is the "generic" version.  The PCI specific version
+ * is in pci.h
+ */
+extern void *consistent_alloc(int gfp, size_t size, dma_addr_t * handle);
+extern void consistent_free(void *vaddr, size_t size, dma_addr_t handle);
+extern void consistent_sync(void *vaddr, size_t size, int rw);
+
+/*
+ * String version of IO memory access ops:
+ */
+extern void _memcpy_fromio(void *, unsigned long, size_t);
+extern void _memcpy_toio(unsigned long, const void *, size_t);
+extern void _memset_io(unsigned long, int, size_t);
+
+extern void __readwrite_bug(const char *fn);
+
+/*
+ * If this architecture has PCI memory IO, then define the read/write
+ * macros.  These should only be used with the cookie passed from
+ * ioremap.
+ */
+#ifdef __mem_pci
+
+#define readb(c) ({ unsigned int __v = __raw_readb(__mem_pci(c)); __v; })
+#define readw(c) ({ unsigned int __v = le16_to_cpu(__raw_readw(__mem_pci(c))); __v; })
+#define readl(c) ({ unsigned int __v = le32_to_cpu(__raw_readl(__mem_pci(c))); __v; })
+
+#define writeb(v,c)		__raw_writeb(v,__mem_pci(c))
+#define writew(v,c)		__raw_writew(cpu_to_le16(v),__mem_pci(c))
+#define writel(v,c)		__raw_writel(cpu_to_le32(v),__mem_pci(c))
+
+#define memset_io(c,v,l)		_memset_io(__mem_pci(c),(v),(l))
+#define memcpy_fromio(a,c,l)		_memcpy_fromio((a),__mem_pci(c),(l))
+#define memcpy_toio(c,a,l)		_memcpy_toio(__mem_pci(c),(a),(l))
+
+#define eth_io_copy_and_sum(s,c,l,b) \
+				eth_copy_and_sum((s),__mem_pci(c),(l),(b))
+
+static inline int check_signature(unsigned long io_addr, const unsigned char *signature, int length)
+{
+    int retval = 0;
+    do
+    {
+        if (readb(io_addr) != *signature)
+            goto out;
+        io_addr++;
+        signature++;
+        length--;
+    }
+    while (length);
+    retval = 1;
+  out:
+    return retval;
+}
+
+#elif !defined(readb)
+
+#define readb(addr)			(__readwrite_bug("readb"),0)
+#define readw(addr)			(__readwrite_bug("readw"),0)
+#define readl(addr)			(__readwrite_bug("readl"),0)
+#define writeb(v,addr)			__readwrite_bug("writeb")
+#define writew(v,addr)			__readwrite_bug("writew")
+#define writel(v,addr)			__readwrite_bug("writel")
+
+#define eth_io_copy_and_sum(a,b,c,d)	__readwrite_bug("eth_io_copy_and_sum")
+
+#define check_signature(io,sig,len)	(0)
+
+#endif                          /* __mem_pci */
+
+/*
+ * If this architecture has ISA IO, then define the isa_read/isa_write
+ * macros.
+ */
+#ifdef __mem_isa
+
+#define isa_readb(addr)			__raw_readb(__mem_isa(addr))
+#define isa_readw(addr)			__raw_readw(__mem_isa(addr))
+#define isa_readl(addr)			__raw_readl(__mem_isa(addr))
+#define isa_writeb(val,addr)		__raw_writeb(val,__mem_isa(addr))
+#define isa_writew(val,addr)		__raw_writew(val,__mem_isa(addr))
+#define isa_writel(val,addr)		__raw_writel(val,__mem_isa(addr))
+#define isa_memset_io(a,b,c)		_memset_io(__mem_isa(a),(b),(c))
+#define isa_memcpy_fromio(a,b,c)	_memcpy_fromio((a),__mem_isa(b),(c))
+#define isa_memcpy_toio(a,b,c)		_memcpy_toio(__mem_isa((a)),(b),(c))
+
+#define isa_eth_io_copy_and_sum(a,b,c,d) \
+				eth_copy_and_sum((a),__mem_isa(b),(c),(d))
+
+static inline int
+isa_check_signature(unsigned long io_addr, const unsigned char *signature, int length)
+{
+    int retval = 0;
+    do
+    {
+        if (isa_readb(io_addr) != *signature)
+            goto out;
+        io_addr++;
+        signature++;
+        length--;
+    }
+    while (length);
+    retval = 1;
+  out:
+    return retval;
+}
+
+#else                           /* __mem_isa */
+
+#define isa_readb(addr)			(__readwrite_bug("isa_readb"),0)
+#define isa_readw(addr)			(__readwrite_bug("isa_readw"),0)
+#define isa_readl(addr)			(__readwrite_bug("isa_readl"),0)
+#define isa_writeb(val,addr)		__readwrite_bug("isa_writeb")
+#define isa_writew(val,addr)		__readwrite_bug("isa_writew")
+#define isa_writel(val,addr)		__readwrite_bug("isa_writel")
+#define isa_memset_io(a,b,c)		__readwrite_bug("isa_memset_io")
+#define isa_memcpy_fromio(a,b,c)	__readwrite_bug("isa_memcpy_fromio")
+#define isa_memcpy_toio(a,b,c)		__readwrite_bug("isa_memcpy_toio")
+
+#define isa_eth_io_copy_and_sum(a,b,c,d) \
+				__readwrite_bug("isa_eth_io_copy_and_sum")
+
+#define isa_check_signature(io,sig,len)	(0)
+
+#endif                          /* __mem_isa */
+#endif                          /* __KERNEL__ */
+#endif                          /* __ASM_ARM_IO_H */
diff --git a/linux-bsp/asm-study/myboot/include/asm/posix_types.h b/linux-bsp/asm-study/myboot/include/asm/posix_types.h
new file mode 100644
index 0000000..1a6554a
--- /dev/null
+++ b/linux-bsp/asm-study/myboot/include/asm/posix_types.h
@@ -0,0 +1,80 @@
+/*
+ *  linux/include/asm-arm/posix_types.h
+ *
+ *  Copyright (C) 1996-1998 Russell King.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ *  Changelog:
+ *   27-06-1996	RMK	Created
+ */
+#ifndef __ARCH_ARM_POSIX_TYPES_H
+#define __ARCH_ARM_POSIX_TYPES_H
+
+/*
+ * This file is generally used by user-level software, so you need to
+ * be a little careful about namespace pollution etc.  Also, we cannot
+ * assume GCC is being used.
+ */
+
+typedef unsigned short __kernel_dev_t;
+typedef unsigned long __kernel_ino_t;
+typedef unsigned short __kernel_mode_t;
+typedef unsigned short __kernel_nlink_t;
+typedef long __kernel_off_t;
+typedef int __kernel_pid_t;
+typedef unsigned short __kernel_ipc_pid_t;
+typedef unsigned short __kernel_uid_t;
+typedef unsigned short __kernel_gid_t;
+typedef unsigned int __kernel_size_t;
+typedef int __kernel_ssize_t;
+typedef int __kernel_ptrdiff_t;
+typedef long __kernel_time_t;
+typedef long __kernel_suseconds_t;
+typedef long __kernel_clock_t;
+typedef int __kernel_daddr_t;
+typedef char *__kernel_caddr_t;
+typedef unsigned short __kernel_uid16_t;
+typedef unsigned short __kernel_gid16_t;
+typedef unsigned int __kernel_uid32_t;
+typedef unsigned int __kernel_gid32_t;
+
+typedef unsigned short __kernel_old_uid_t;
+typedef unsigned short __kernel_old_gid_t;
+
+#ifdef __GNUC__
+typedef long long __kernel_loff_t;
+#endif
+
+typedef struct
+{
+#if defined(__KERNEL__) || defined(__USE_ALL)
+    int val[2];
+#else                           /* !defined(__KERNEL__) && !defined(__USE_ALL) */
+    int __val[2];
+#endif                          /* !defined(__KERNEL__) && !defined(__USE_ALL) */
+} __kernel_fsid_t;
+
+#if defined(__KERNEL__) || !defined(__GLIBC__) || (__GLIBC__ < 2)
+
+#undef	__FD_SET
+#define __FD_SET(fd, fdsetp) \
+		(((fd_set *)fdsetp)->fds_bits[fd >> 5] |= (1<<(fd & 31)))
+
+#undef	__FD_CLR
+#define __FD_CLR(fd, fdsetp) \
+		(((fd_set *)fdsetp)->fds_bits[fd >> 5] &= ~(1<<(fd & 31)))
+
+#undef	__FD_ISSET
+#define __FD_ISSET(fd, fdsetp) \
+		((((fd_set *)fdsetp)->fds_bits[fd >> 5] & (1<<(fd & 31))) != 0)
+
+#undef	__FD_ZERO
+#define __FD_ZERO(fdsetp) \
+		(memset (fdsetp, 0, sizeof (*(fd_set *)fdsetp)))
+
+#endif
+
+#endif
diff --git a/linux-bsp/asm-study/myboot/include/asm/sizes.h b/linux-bsp/asm-study/myboot/include/asm/sizes.h
new file mode 100644
index 0000000..f8d92ca
--- /dev/null
+++ b/linux-bsp/asm-study/myboot/include/asm/sizes.h
@@ -0,0 +1,52 @@
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+/* DO NOT EDIT!! - this file automatically generated
+ *                 from .s file by awk -f s2h.awk
+ */
+/*  Size defintions
+ *  Copyright (C) ARM Limited 1998. All rights reserved.
+ */
+
+#ifndef __sizes_h
+#define __sizes_h                       1
+
+/* handy sizes */
+#define SZ_1K                           0x00000400
+#define SZ_4K                           0x00001000
+#define SZ_8K                           0x00002000
+#define SZ_16K                          0x00004000
+#define SZ_64K                          0x00010000
+#define SZ_128K                         0x00020000
+#define SZ_256K                         0x00040000
+#define SZ_512K                         0x00080000
+
+#define SZ_1M                           0x00100000
+#define SZ_2M                           0x00200000
+#define SZ_4M                           0x00400000
+#define SZ_8M                           0x00800000
+#define SZ_16M                          0x01000000
+#define SZ_32M                          0x02000000
+#define SZ_64M                          0x04000000
+#define SZ_128M                         0x08000000
+#define SZ_256M                         0x10000000
+#define SZ_512M                         0x20000000
+
+#define SZ_1G                           0x40000000
+#define SZ_2G                           0x80000000
+
+#endif
+
+/*         END */
diff --git a/linux-bsp/asm-study/myboot/include/asm/types.h b/linux-bsp/asm-study/myboot/include/asm/types.h
new file mode 100644
index 0000000..27b55b2
--- /dev/null
+++ b/linux-bsp/asm-study/myboot/include/asm/types.h
@@ -0,0 +1,53 @@
+#ifndef __ASM_ARM_TYPES_H
+#define __ASM_ARM_TYPES_H
+
+typedef unsigned short umode_t;
+
+/*
+ * __xx is ok: it doesn't pollute the POSIX namespace. Use these in the
+ * header files exported to user space
+ */
+
+typedef __signed__ char __s8;
+typedef unsigned char __u8;
+
+typedef __signed__ short __s16;
+typedef unsigned short __u16;
+
+typedef __signed__ int __s32;
+typedef unsigned int __u32;
+
+#if defined(__GNUC__)
+__extension__ typedef __signed__ long long __s64;
+__extension__ typedef unsigned long long __u64;
+#endif
+
+/*
+ * These aren't exported outside the kernel to avoid name space clashes
+ */
+#ifdef __KERNEL__
+
+typedef signed char s8;
+typedef unsigned char u8;
+
+typedef signed short s16;
+typedef unsigned short u16;
+
+typedef signed int s32;
+typedef unsigned int u32;
+
+typedef signed long long s64;
+typedef unsigned long long u64;
+
+#define BITS_PER_LONG 32
+
+/* Dma addresses are 32-bits wide.  */
+
+typedef u32 dma_addr_t;
+
+typedef unsigned long phys_addr_t;
+typedef unsigned long phys_size_t;
+
+#endif                          /* __KERNEL__ */
+
+#endif
diff --git a/linux-bsp/asm-study/myboot/include/bignum.h b/linux-bsp/asm-study/myboot/include/bignum.h
new file mode 100644
index 0000000..3ffa5cb
--- /dev/null
+++ b/linux-bsp/asm-study/myboot/include/bignum.h
@@ -0,0 +1,380 @@
+/**
+ * \file bignum.h
+ */
+#ifndef _BIGNUM_H
+#define _BIGNUM_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define ERR_MPI_INVALID_CHARACTER               0x0002
+#define ERR_MPI_INVALID_PARAMETER               0x0004
+#define ERR_MPI_BUFFER_TOO_SMALL                0x0006
+#define ERR_MPI_NEGATIVE_VALUE                  0x0008
+#define ERR_MPI_DIVISION_BY_ZERO                0x000A
+#define ERR_MPI_NOT_INVERTIBLE                  0x000C
+#define ERR_MPI_IS_COMPOSITE                    0x000E
+
+#define CHK(fc) if( ( ret = fc ) != 0 ) goto cleanup
+
+/*
+ * Define the base limb type
+ */
+#if defined(HAVE_INT16) /* 8086 */
+typedef unsigned int  t_int;
+typedef unsigned long t_dbl;
+#else
+typedef unsigned long t_int;
+typedef unsigned long long t_dbl;
+#endif
+
+#define ciL    (int) sizeof(t_int)      /* chars in limb  */
+#define biL    (ciL << 3)               /* bits  in limb  */
+#define biH    (ciL << 2)               /* half limb size */
+
+/**
+ * \brief          MPI structure
+ */
+typedef struct
+{
+    int s;              /*!<  integer sign      */
+    int n;              /*!<  total # of limbs  */
+//    t_int *p;           /*!<  pointer to limbs  */
+    unsigned long long *p;           /*!<  pointer to limbs  */
+}
+mpi;
+
+/**
+ * \brief          Initialize one or more mpi
+ */
+void mpi_init( mpi *X, ... );
+
+/**
+ * \brief          Unallocate one or more mpi
+ */
+void mpi_free( mpi *X, ... );
+
+/**
+ * \brief          Enlarge X to the specified # of limbs
+ *
+ * \return         0 if successful,
+ *                 1 if memory allocation failed
+ */
+int mpi_grow( mpi *X, int nblimbs );
+
+/**
+ * \brief          Copy the contents of Y into X
+ *
+ * \return         0 if successful,
+ *                 1 if memory allocation failed
+ */
+int mpi_copy( mpi *X, mpi *Y );
+
+/**
+ * \brief          Swap the contents of X and Y
+ */
+void mpi_swap( mpi *X, mpi *Y );
+
+/**
+ * \brief          Set value from integer
+ *
+ * \return         0 if successful,
+ *                 1 if memory allocation failed
+ */
+int mpi_lset( mpi *X, int z );
+
+/**
+ * \brief          Set value from string
+ *
+ * \param X        destination mpi
+ * \param s        string to read the value from
+ * \param radix    numeric base of "s"
+ *
+ * \return         0 if successful,
+ *                 1 if memory allocation failed,
+ *                 ERR_MPI_INVALID_PARAMETER if the radix is invalid
+ *                 ERR_MPI_INVALID_CHARACTER if a non-digit is found
+ */
+int mpi_read( mpi *X, char *s, int radix );
+
+/**
+ * \brief          Print the value of X into fout
+ *
+ * \param name     string printed before the value
+ * \param X        mpi to be printed
+ * \param radix    chosen numeric base
+ * \param fout     output file stream
+ *
+ * \return         0 if successful,
+ *                 1 if memory allocation failed,
+ *                 ERR_MPI_INVALID_PARAMETER if the radix is invalid
+ */
+int mpi_showf( char *name, mpi *X, int radix, FILE *fout );
+
+/**
+ * \brief          Print the value of X on the console
+ *
+ * \param name     string printed before the value
+ * \param X        mpi to be printed
+ * \param radix    chosen numeric base
+ *
+ * \return         0 if successful,
+ *                 1 if memory allocation failed,
+ *                 ERR_MPI_INVALID_PARAMETER if the radix is invalid
+ */
+int mpi_show( char *name, mpi *X, int radix );
+
+/**
+ * \brief          Import an unsigned value from binary data
+ *
+ * \param X        destination mpi
+ * \param buf      input buffer
+ * \param buflen   size of buffer
+ *
+ * \return         0 if successful,
+ *                 1 if memory allocation failed
+ */
+int mpi_import( mpi *X, unsigned char *buf, int buflen );
+
+/**
+ * \brief          Export an unsigned value into binary data
+ *
+ * \param X        source mpi
+ * \param buf      output buffer
+ * \param buflen   size of buffer
+ *
+ * \return         0 if successful,
+ *                 ERR_MPI_BUFFER_TOO_SMALL if buf isn't large enough
+ *
+ * \note           Call this function with *buflen = 0 to obtain the
+ *                 required buffer size in *buflen.
+ */
+int mpi_export( mpi *X, unsigned char *buf, int *buflen );
+
+/**
+ * \brief          Return actual size in bits (without leading 0s)
+ */
+int mpi_size( mpi *X );
+
+/**
+ * \brief          Return number of least significant bits
+ */
+int mpi_lsb( mpi *X );
+
+/**
+ * \brief          Left-shift: X <<= count
+ *
+ * \return         0 if successful,
+ *                 1 if memory allocation failed
+ */
+int mpi_shift_l( mpi *X, int count );
+
+/**
+ * \brief          Right-shift: X >>= count
+ *
+ * \return         0 if successful,
+ *                 1 if memory allocation failed
+ */
+int mpi_shift_r( mpi *X, int count );
+
+/**
+ * \brief          Compare unsigned values
+ *
+ * \return         1 if |X| is greater than |Y|,
+ *                -1 if |X| is lesser  than |Y| or
+ *                 0 if |X| is equal to |Y|
+ */
+int mpi_cmp_abs( mpi *X, mpi *Y );
+
+/**
+ * \brief          Compare signed values
+ *
+ * \return         1 if X is greater than Y,
+ *                -1 if X is lesser  than Y or
+ *                 0 if X is equal to Y
+ */
+int mpi_cmp_mpi( mpi *X, mpi *Y );
+
+/**
+ * \brief          Compare signed values
+ *
+ * \return         1 if X is greater than z,
+ *                -1 if X is lesser  than z or
+ *                 0 if X is equal to z
+ */
+int mpi_cmp_int( mpi *X, int z );
+
+/**
+ * \brief          Unsigned addition: X = |A| + |B|
+ *
+ * \return         0 if successful,
+ *                 1 if memory allocation failed
+ */
+int mpi_add_abs( mpi *X, mpi *A, mpi *B );
+
+/**
+ * \brief          Unsigned substraction: X = |A| - |B|
+ *
+ * \return         0 if successful,
+ *                 ERR_MPI_NEGATIVE_VALUE if B is greater than A
+ */
+int mpi_sub_abs( mpi *X, mpi *A, mpi *B );
+
+/**
+ * \brief          Signed addition: X = A + B
+ *
+ * \return         0 if successful,
+ *                 1 if memory allocation failed
+ */
+int mpi_add_mpi( mpi *X, mpi *A, mpi *B );
+
+/**
+ * \brief          Signed substraction: X = A - B
+ *
+ * \return         0 if successful,
+ *                 1 if memory allocation failed
+ */
+int mpi_sub_mpi( mpi *X, mpi *A, mpi *B );
+
+/**
+ * \brief          Signed addition: X = A + b
+ *
+ * \return         0 if successful,
+ *                 1 if memory allocation failed
+ */
+int mpi_add_int( mpi *X, mpi *A, int b );
+
+/**
+ * \brief          Signed substraction: X = A - b
+ *
+ * \return         0 if successful,
+ *                 1 if memory allocation failed
+ */
+int mpi_sub_int( mpi *X, mpi *A, int b );
+
+/**
+ * \brief          Baseline multiplication: X = A * B
+ *
+ * \return         0 if successful,
+ *                 1 if memory allocation failed
+ */
+int mpi_mul_mpi( mpi *X, mpi *A, mpi *B );
+
+/**
+ * \brief          Baseline multiplication: X = A * b
+ *
+ * \return         0 if successful,
+ *                 1 if memory allocation failed
+ */
+int mpi_mul_int( mpi *X, mpi *A, t_int b );
+
+/**
+ * \brief          Division by mpi: A = Q * B + R
+ *
+ * \return         0 if successful,
+ *                 1 if memory allocation failed,
+ *                 ERR_MPI_DIVISION_BY_ZERO if B == 0
+ *
+ * \note           Either Q or R can be NULL.
+ */
+int mpi_div_mpi( mpi *Q, mpi *R, mpi *A, mpi *B );
+
+/**
+ * \brief          Division by int: A = Q * b + R
+ *
+ * \return         0 if successful,
+ *                 1 if memory allocation failed,
+ *                 ERR_MPI_DIVISION_BY_ZERO if b == 0
+ *
+ * \note           Either Q or R can be NULL.
+ */
+int mpi_div_int( mpi *Q, mpi *R, mpi *A, int b );
+
+/**
+ * \brief          Modulo: R = A mod B
+ *
+ * \return         0 if successful,
+ *                 1 if memory allocation failed,
+ *                 ERR_MPI_DIVISION_BY_ZERO if B == 0
+ */
+int mpi_mod_mpi( mpi *R, mpi *A, mpi *B );
+
+/**
+ * \brief          Modulo: r = A mod b
+ *
+ * \return         0 if successful,
+ *                 1 if memory allocation failed,
+ *                 ERR_MPI_DIVISION_BY_ZERO if b == 0,
+ */
+int mpi_mod_int( t_int *r, mpi *A, int b );
+
+/**
+ * \brief          Sliding-window exponentiation: X = A^E mod N
+ *
+ * \return         0 if successful,
+ *                 1 if memory allocation failed,
+ *                 ERR_MPI_INVALID_PARAMETER if N is negative or even
+ *
+ * \note           _RR is used to avoid re-computing R*R mod N across
+ *                 multiple calls, which speeds up things a bit. It can
+ *                 be set to NULL if the extra performance is unneeded.
+ */
+int mpi_exp_mod( mpi *X, mpi *A, mpi *E, mpi *N, mpi *_RR );
+
+/**
+ * \brief          Greatest common divisor: G = gcd(A, B)
+ *
+ * \return         0 if successful,
+ *                 1 if memory allocation failed
+ */
+int mpi_gcd( mpi *G, mpi *A, mpi *B );
+
+/**
+ * \brief          Modular inverse: X = A^-1 mod N
+ *
+ * \return         0 if successful,
+ *                 1 if memory allocation failed,
+ *                 ERR_MPI_INVALID_PARAMETER if N is negative or nil
+ *                 ERR_MPI_NOT_INVERTIBLE if A has no inverse mod N
+ */
+int mpi_inv_mod( mpi *X, mpi *A, mpi *N );
+
+/**
+ * \brief          Miller-Rabin primality test
+ *
+ * \return         0 if successful (probably prime),
+ *                 1 if memory allocation failed,
+ *                 ERR_MPI_IS_COMPOSITE if X is not prime
+ */
+int mpi_is_prime( mpi *X );
+
+/**
+ * \brief          Prime number generation
+ *
+ * \param X        destination mpi
+ * \param nbits    required size of X in bits
+ * \param dh_flag  set this to 1 if (X-1)/2 must also be prime
+ *                 (needed for Diffie-Hellman)
+ * \param rng_f    points to the RNG function
+ * \param rng_d    points to the RNG data 
+ *
+ * \return         0 if successful (probably prime),
+ *                 1 if memory allocation failed,
+ *                 ERR_MPI_INVALID_PARAMETER if nbits is < 3
+ */
+int mpi_gen_prime( mpi *X, int nbits, int dh_flag,
+                   int (*rng_f)(void *), void *rng_d );
+
+/**
+ * \brief          Checkup routine
+ *
+ * \return         0 if successful, or 1 if the test failed
+ */
+int mpi_self_test( void );
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* bignum.h */
diff --git a/linux-bsp/asm-study/myboot/include/bn_asm.h b/linux-bsp/asm-study/myboot/include/bn_asm.h
new file mode 100644
index 0000000..10484e0
--- /dev/null
+++ b/linux-bsp/asm-study/myboot/include/bn_asm.h
@@ -0,0 +1,549 @@
+/**
+ * \file bn_asm.h
+ *
+ *      Multiply source vector [s] with b, add result
+ *       to destination vector [d] and set carry c.
+ */
+#ifndef _BN_ASM_H
+#define _BN_ASM_H
+
+#if defined(__GNUC__)
+#if defined(__i386__)
+
+#define MULADDC_INIT                            \
+    asm( "movl   %0, %%esi      " :: "m" (s));  \
+    asm( "movl   %0, %%edi      " :: "m" (d));  \
+    asm( "movl   %0, %%ecx      " :: "m" (c));  \
+    asm( "movl   %0, %%ebx      " :: "m" (b));
+
+#define MULADDC_CORE                            \
+    asm( "lodsl                 " );            \
+    asm( "mull   %ebx           " );            \
+    asm( "addl   %ecx,   %eax   " );            \
+    asm( "adcl   $0,     %edx   " );            \
+    asm( "addl   (%edi), %eax   " );            \
+    asm( "adcl   $0,     %edx   " );            \
+    asm( "movl   %edx,   %ecx   " );            \
+    asm( "stosl                 " );
+
+#define MULADDC_STOP                            \
+    asm( "movl   %%ecx, %0      " : "=m" (c));  \
+    asm( "movl   %%edi, %0      " : "=m" (d));  \
+    asm( "movl   %%esi, %0      " : "=m" (s) :: \
+    "eax", "ecx", "edx", "ebx", "esi", "edi" );
+
+#if defined(HAVE_SSE2)
+
+#define MULADDC_HUIT                            \
+    asm( "movd     %ecx,     %mm1     " );      \
+    asm( "movd     %ebx,     %mm0     " );      \
+    asm( "movd     (%edi),   %mm3     " );      \
+    asm( "paddq    %mm3,     %mm1     " );      \
+    asm( "movd     (%esi),   %mm2     " );      \
+    asm( "pmuludq  %mm0,     %mm2     " );      \
+    asm( "movd     4(%esi),  %mm4     " );      \
+    asm( "pmuludq  %mm0,     %mm4     " );      \
+    asm( "movd     8(%esi),  %mm6     " );      \
+    asm( "pmuludq  %mm0,     %mm6     " );      \
+    asm( "movd     12(%esi), %mm7     " );      \
+    asm( "pmuludq  %mm0,     %mm7     " );      \
+    asm( "paddq    %mm2,     %mm1     " );      \
+    asm( "movd     4(%edi),  %mm3     " );      \
+    asm( "paddq    %mm4,     %mm3     " );      \
+    asm( "movd     8(%edi),  %mm5     " );      \
+    asm( "paddq    %mm6,     %mm5     " );      \
+    asm( "movd     12(%edi), %mm4     " );      \
+    asm( "paddq    %mm4,     %mm7     " );      \
+    asm( "movd     %mm1,     (%edi)   " );      \
+    asm( "movd     16(%esi), %mm2     " );      \
+    asm( "pmuludq  %mm0,     %mm2     " );      \
+    asm( "psrlq    $32,      %mm1     " );      \
+    asm( "movd     20(%esi), %mm4     " );      \
+    asm( "pmuludq  %mm0,     %mm4     " );      \
+    asm( "paddq    %mm3,     %mm1     " );      \
+    asm( "movd     24(%esi), %mm6     " );      \
+    asm( "pmuludq  %mm0,     %mm6     " );      \
+    asm( "movd     %mm1,     4(%edi)  " );      \
+    asm( "psrlq    $32,      %mm1     " );      \
+    asm( "movd     28(%esi), %mm3     " );      \
+    asm( "pmuludq  %mm0,     %mm3     " );      \
+    asm( "paddq    %mm5,     %mm1     " );      \
+    asm( "movd     16(%edi), %mm5     " );      \
+    asm( "paddq    %mm5,     %mm2     " );      \
+    asm( "movd     %mm1,     8(%edi)  " );      \
+    asm( "psrlq    $32,      %mm1     " );      \
+    asm( "paddq    %mm7,     %mm1     " );      \
+    asm( "movd     20(%edi), %mm5     " );      \
+    asm( "paddq    %mm5,     %mm4     " );      \
+    asm( "movd     %mm1,     12(%edi) " );      \
+    asm( "psrlq    $32,      %mm1     " );      \
+    asm( "paddq    %mm2,     %mm1     " );      \
+    asm( "movd     24(%edi), %mm5     " );      \
+    asm( "paddq    %mm5,     %mm6     " );      \
+    asm( "movd     %mm1,     16(%edi) " );      \
+    asm( "psrlq    $32,      %mm1     " );      \
+    asm( "paddq    %mm4,     %mm1     " );      \
+    asm( "movd     28(%edi), %mm5     " );      \
+    asm( "paddq    %mm5,     %mm3     " );      \
+    asm( "movd     %mm1,     20(%edi) " );      \
+    asm( "psrlq    $32,      %mm1     " );      \
+    asm( "paddq    %mm6,     %mm1     " );      \
+    asm( "movd     %mm1,     24(%edi) " );      \
+    asm( "psrlq    $32,      %mm1     " );      \
+    asm( "paddq    %mm3,     %mm1     " );      \
+    asm( "movd     %mm1,     28(%edi) " );      \
+    asm( "addl     $32,      %edi     " );      \
+    asm( "addl     $32,      %esi     " );      \
+    asm( "psrlq    $32,      %mm1     " );      \
+    asm( "movd     %mm1,     %ecx     " );
+
+#endif /* SSE2 */
+#endif /* i386 */
+
+#if defined(__amd64__) || defined (__x86_64__)
+
+#define MULADDC_INIT                            \
+    asm( "movq   %0, %%rsi      " :: "m" (s));  \
+    asm( "movq   %0, %%rdi      " :: "m" (d));  \
+    asm( "movq   %0, %%rcx      " :: "m" (c));  \
+    asm( "movq   %0, %%rbx      " :: "m" (b));  \
+    asm( "xorq   %r8, %r8       " );
+
+#define MULADDC_CORE                            \
+    asm( "movq  (%rsi),%rax     " );            \
+    asm( "mulq   %rbx           " );            \
+    asm( "addq   $8,   %rsi     " );            \
+    asm( "addq   %rcx, %rax     " );            \
+    asm( "movq   %r8,  %rcx     " );            \
+    asm( "adcq   $0,   %rdx     " );            \
+    asm( "nop                   " );            \
+    asm( "addq   %rax, (%rdi)   " );            \
+    asm( "adcq   %rdx, %rcx     " );            \
+    asm( "addq   $8,   %rdi     " );
+
+#define MULADDC_STOP                            \
+    asm( "movq   %%rcx, %0      " : "=m" (c));  \
+    asm( "movq   %%rdi, %0      " : "=m" (d));  \
+    asm( "movq   %%rsi, %0      " : "=m" (s) :: \
+    "rax", "rcx", "rdx", "rbx", "rsi", "rdi", "r8" );
+
+#endif /* AMD64 */
+
+#if defined(__mc68020__) || defined(__mcpu32__)
+
+#define MULADDC_INIT                            \
+    asm( "movl   %0, %%a2       " :: "m" (s));  \
+    asm( "movl   %0, %%a3       " :: "m" (d));  \
+    asm( "movl   %0, %%d3       " :: "m" (c));  \
+    asm( "movl   %0, %%d2       " :: "m" (b));  \
+    asm( "moveq  #0, %d0        " );
+
+#define MULADDC_CORE                            \
+    asm( "movel  %a2@+, %d1     " );            \
+    asm( "mulul  %d2, %d4:%d1   " );            \
+    asm( "addl   %d3, %d1       " );            \
+    asm( "addxl  %d0, %d4       " );            \
+    asm( "moveq  #0,  %d3       " );            \
+    asm( "addl   %d1, %a3@+     " );            \
+    asm( "addxl  %d4, %d3       " );
+
+#define MULADDC_STOP                            \
+    asm( "movl   %%d3, %0       " : "=m" (c));  \
+    asm( "movl   %%a3, %0       " : "=m" (d));  \
+    asm( "movl   %%a2, %0       " : "=m" (s) :: \
+    "d0", "d1", "d2", "d3", "d4", "a2", "a3" );
+
+#define MULADDC_HUIT                            \
+    asm( "movel  %a2@+, %d1     " );            \
+    asm( "mulul  %d2, %d4:%d1   " );            \
+    asm( "addxl  %d3, %d1       " );            \
+    asm( "addxl  %d0, %d4       " );            \
+    asm( "addl   %d1, %a3@+     " );            \
+    asm( "movel  %a2@+, %d1     " );            \
+    asm( "mulul  %d2, %d3:%d1   " );            \
+    asm( "addxl  %d4, %d1       " );            \
+    asm( "addxl  %d0, %d3       " );            \
+    asm( "addl   %d1, %a3@+     " );            \
+    asm( "movel  %a2@+, %d1     " );            \
+    asm( "mulul  %d2, %d4:%d1   " );            \
+    asm( "addxl  %d3, %d1       " );            \
+    asm( "addxl  %d0, %d4       " );            \
+    asm( "addl   %d1, %a3@+     " );            \
+    asm( "movel  %a2@+, %d1     " );            \
+    asm( "mulul  %d2, %d3:%d1   " );            \
+    asm( "addxl  %d4, %d1       " );            \
+    asm( "addxl  %d0, %d3       " );            \
+    asm( "addl   %d1, %a3@+     " );            \
+    asm( "movel  %a2@+, %d1     " );            \
+    asm( "mulul  %d2, %d4:%d1   " );            \
+    asm( "addxl  %d3, %d1       " );            \
+    asm( "addxl  %d0, %d4       " );            \
+    asm( "addl   %d1, %a3@+     " );            \
+    asm( "movel  %a2@+, %d1     " );            \
+    asm( "mulul  %d2, %d3:%d1   " );            \
+    asm( "addxl  %d4, %d1       " );            \
+    asm( "addxl  %d0, %d3       " );            \
+    asm( "addl   %d1, %a3@+     " );            \
+    asm( "movel  %a2@+, %d1     " );            \
+    asm( "mulul  %d2, %d4:%d1   " );            \
+    asm( "addxl  %d3, %d1       " );            \
+    asm( "addxl  %d0, %d4       " );            \
+    asm( "addl   %d1, %a3@+     " );            \
+    asm( "movel  %a2@+, %d1     " );            \
+    asm( "mulul  %d2, %d3:%d1   " );            \
+    asm( "addxl  %d4, %d1       " );            \
+    asm( "addxl  %d0, %d3       " );            \
+    asm( "addl   %d1, %a3@+     " );            \
+    asm( "addxl  %d0, %d3       " );
+
+#endif /* MC68020 */
+
+#if defined(__powerpc__)   || defined(__ppc__)
+#if defined(__powerpc64__) || defined(__ppc64__)
+
+#define MULADDC_INIT                            \
+    asm( "ld     %%r3, %0       " :: "m" (s));  \
+    asm( "ld     %%r4, %0       " :: "m" (d));  \
+    asm( "ld     %%r5, %0       " :: "m" (c));  \
+    asm( "ld     %%r6, %0       " :: "m" (b));  \
+    asm( "addi   %r3, %r3, -8   " );            \
+    asm( "addi   %r4, %r4, -8   " );            \
+    asm( "addic  %r5, %r5,  0   " );
+
+#define MULADDC_CORE                            \
+    asm( "ldu    %r7, 8(%r3)    " );            \
+    asm( "mulld  %r8, %r7, %r6  " );            \
+    asm( "mulhdu %r9, %r7, %r6  " );            \
+    asm( "adde   %r8, %r8, %r5  " );            \
+    asm( "ld     %r7, 8(%r4)    " );            \
+    asm( "addze  %r5, %r9       " );            \
+    asm( "addc   %r8, %r8, %r7  " );            \
+    asm( "stdu   %r8, 8(%r4)    " );
+
+#define MULADDC_STOP                            \
+    asm( "addze  %r5, %r5       " );            \
+    asm( "addi   %r4, %r4, 8    " );            \
+    asm( "addi   %r3, %r3, 8    " );            \
+    asm( "std    %%r5, %0       " : "=m" (c));  \
+    asm( "std    %%r4, %0       " : "=m" (d));  \
+    asm( "std    %%r3, %0       " : "=m" (s) :: \
+    "r3", "r4", "r5", "r6", "r7", "r8", "r9" );
+
+#else
+
+#define MULADDC_INIT                            \
+    asm( "lwz    %%r3, %0       " :: "m" (s));  \
+    asm( "lwz    %%r4, %0       " :: "m" (d));  \
+    asm( "lwz    %%r5, %0       " :: "m" (c));  \
+    asm( "lwz    %%r6, %0       " :: "m" (b));  \
+    asm( "addi   %r3, %r3, -4   " );            \
+    asm( "addi   %r4, %r4, -4   " );            \
+    asm( "addic  %r5, %r5,  0   " );
+
+#define MULADDC_CORE                            \
+    asm( "lwzu   %r7, 4(%r3)    " );            \
+    asm( "mullw  %r8, %r7, %r6  " );            \
+    asm( "mulhwu %r9, %r7, %r6  " );            \
+    asm( "adde   %r8, %r8, %r5  " );            \
+    asm( "lwz    %r7, 4(%r4)    " );            \
+    asm( "addze  %r5, %r9       " );            \
+    asm( "addc   %r8, %r8, %r7  " );            \
+    asm( "stwu   %r8, 4(%r4)    " );
+
+#define MULADDC_STOP                            \
+    asm( "addze  %r5, %r5       " );            \
+    asm( "addi   %r4, %r4, 4    " );            \
+    asm( "addi   %r3, %r3, 4    " );            \
+    asm( "stw    %%r5, %0       " : "=m" (c));  \
+    asm( "stw    %%r4, %0       " : "=m" (d));  \
+    asm( "stw    %%r3, %0       " : "=m" (s) :: \
+    "r3", "r4", "r5", "r6", "r7", "r8", "r9" );
+
+#endif /* PowerPC 32-bit */
+#endif /* PowerPC 64-bit */
+
+#if defined(__sparc__)
+
+#define MULADDC_INIT                            \
+    asm( "ld     %0, %%o0       " :: "m" (s));  \
+    asm( "ld     %0, %%o1       " :: "m" (d));  \
+    asm( "ld     %0, %%o2       " :: "m" (c));  \
+    asm( "ld     %0, %%o3       " :: "m" (b));
+
+#define MULADDC_CORE                            \
+    asm( "ld    [%o0], %o4      " );            \
+    asm( "inc      4,  %o0      " );            \
+    asm( "ld    [%o1], %o5      " );            \
+    asm( "umul   %o3,  %o4, %o4 " );            \
+    asm( "addcc  %o4,  %o2, %o4 " );            \
+    asm( "rd      %y,  %g1      " );            \
+    asm( "addx   %g1,    0, %g1 " );            \
+    asm( "addcc  %o4,  %o5, %o4 " );            \
+    asm( "st     %o4, [%o1]     " );            \
+    asm( "addx   %g1,    0, %o2 " );            \
+    asm( "inc      4,  %o1      " );
+
+#define MULADDC_STOP                            \
+    asm( "st     %%o2, %0       " : "=m" (c));  \
+    asm( "st     %%o1, %0       " : "=m" (d));  \
+    asm( "st     %%o0, %0       " : "=m" (s) :: \
+    "g1", "o0", "o1", "o2", "o3", "o4", "o5" );
+
+#endif /* SPARC8 */
+
+#if defined(__tricore__)
+
+#define MULADDC_INIT                            \
+    asm( "ld.a   %%a2, %0       " :: "m" (s));  \
+    asm( "ld.a   %%a3, %0       " :: "m" (d));  \
+    asm( "ld.w   %%d4, %0       " :: "m" (c));  \
+    asm( "ld.w   %%d1, %0       " :: "m" (b));  \
+    asm( "xor    %d5, %d5       " );
+
+#define MULADDC_CORE                            \
+    asm( "ld.w   %d0,   [%a2+]      " );        \
+    asm( "madd.u %e2, %e4, %d0, %d1 " );        \
+    asm( "ld.w   %d0,   [%a3]       " );        \
+    asm( "addx   %d2,    %d2,  %d0  " );        \
+    asm( "addc   %d3,    %d3,    0  " );        \
+    asm( "mov    %d4,    %d3        " );        \
+    asm( "st.w  [%a3+],  %d2        " );
+
+#define MULADDC_STOP                            \
+    asm( "st.w   %0, %%d4       " : "=m" (c));  \
+    asm( "st.a   %0, %%a3       " : "=m" (d));  \
+    asm( "st.a   %0, %%a2       " : "=m" (s) :: \
+    "d0", "d1", "e2", "d4", "a2", "a3" );
+
+#endif /* TriCore */
+
+#if defined(__arm__)
+
+#define MULADDC_INIT                            \
+    asm( "ldr    r0, %0         " :: "m" (s));  \
+    asm( "ldr    r1, %0         " :: "m" (d));  \
+    asm( "ldr    r2, %0         " :: "m" (c));  \
+    asm( "ldr    r3, %0         " :: "m" (b));
+
+#define MULADDC_CORE                            \
+    asm( "ldr    r4, [r0], #4   " );            \
+    asm( "mov    r5, #0         " );            \
+    asm( "ldr    r6, [r1]       " );            \
+    asm( "umlal  r2, r5, r3, r4 " );            \
+    asm( "adds   r7, r6, r2     " );            \
+    asm( "adc    r2, r5, #0     " );            \
+    asm( "str    r7, [r1], #4   " );
+
+#define MULADDC_STOP                            \
+    asm( "str    r2, %0         " : "=m" (c));  \
+    asm( "str    r1, %0         " : "=m" (d));  \
+    asm( "str    r0, %0         " : "=m" (s) :: \
+    "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7" );
+
+#endif /* ARMv3 */
+
+#if defined(__alpha__)
+
+#define MULADDC_INIT                            \
+    asm( "ldq    $1, %0         " :: "m" (s));  \
+    asm( "ldq    $2, %0         " :: "m" (d));  \
+    asm( "ldq    $3, %0         " :: "m" (c));  \
+    asm( "ldq    $4, %0         " :: "m" (b));
+
+#define MULADDC_CORE                            \
+    asm( "ldq    $6,  0($1)     " );            \
+    asm( "addq   $1,  8, $1     " );            \
+    asm( "mulq   $6, $4, $7     " );            \
+    asm( "umulh  $6, $4, $6     " );            \
+    asm( "addq   $7, $3, $7     " );            \
+    asm( "cmpult $7, $3, $3     " );            \
+    asm( "ldq    $5,  0($2)     " );            \
+    asm( "addq   $7, $5, $7     " );            \
+    asm( "cmpult $7, $5, $5     " );            \
+    asm( "stq    $7,  0($2)     " );            \
+    asm( "addq   $2,  8, $2     " );            \
+    asm( "addq   $6, $3, $3     " );            \
+    asm( "addq   $5, $3, $3     " );
+
+#define MULADDC_STOP                            \
+    asm( "stq    $3, %0         " : "=m" (c));  \
+    asm( "stq    $2, %0         " : "=m" (d));  \
+    asm( "stq    $1, %0         " : "=m" (s) :: \
+    "$1", "$2", "$3", "$4", "$5", "$6", "$7" );
+
+#endif /* Alpha */
+
+#if defined(__mips__)
+
+#define MULADDC_INIT                            \
+    asm( "lw     $10, %0        " :: "m" (s));  \
+    asm( "lw     $11, %0        " :: "m" (d));  \
+    asm( "lw     $12, %0        " :: "m" (c));  \
+    asm( "lw     $13, %0        " :: "m" (b));
+
+#define MULADDC_CORE                            \
+    asm( "lw     $14, 0($10)    " );            \
+    asm( "multu  $13, $14       " );            \
+    asm( "addi   $10, $10, 4    " );            \
+    asm( "mflo   $14            " );            \
+    asm( "mfhi   $9             " );            \
+    asm( "addu   $14, $12, $14  " );            \
+    asm( "lw     $15, 0($11)    " );            \
+    asm( "sltu   $12, $14, $12  " );            \
+    asm( "addu   $15, $14, $15  " );            \
+    asm( "sltu   $14, $15, $14  " );            \
+    asm( "addu   $12, $12, $9   " );            \
+    asm( "sw     $15, 0($11)    " );            \
+    asm( "addu   $12, $12, $14  " );            \
+    asm( "addi   $11, $11, 4    " );
+
+#define MULADDC_STOP                            \
+    asm( "sw     $12, %0        " : "=m" (c));  \
+    asm( "sw     $11, %0        " : "=m" (d));  \
+    asm( "sw     $10, %0        " : "=m" (s) :: \
+    "$9", "$10", "$11", "$12", "$13", "$14", "$15" );
+
+#endif /* MIPS */
+#endif /* GNUC */
+
+#if (defined(_MSC_VER) && defined(_M_IX86)) || defined(__WATCOMC__)
+
+#define MULADDC_INIT                            \
+    __asm   mov     esi, s                      \
+    __asm   mov     edi, d                      \
+    __asm   mov     ecx, c                      \
+    __asm   mov     ebx, b
+
+#define MULADDC_CORE                            \
+    __asm   lodsd                               \
+    __asm   mul     ebx                         \
+    __asm   add     eax, ecx                    \
+    __asm   adc     edx, 0                      \
+    __asm   add     eax, [edi]                  \
+    __asm   adc     edx, 0                      \
+    __asm   mov     ecx, edx                    \
+    __asm   stosd
+
+#define MULADDC_STOP                            \
+    __asm   mov     c, ecx                      \
+    __asm   mov     d, edi                      \
+    __asm   mov     s, esi                      \
+
+#if defined HAVE_SSE2
+
+#define EMIT __asm _emit
+
+#define MULADDC_HUIT                            \
+    EMIT 0x0F  EMIT 0x6E  EMIT 0xC9             \
+    EMIT 0x0F  EMIT 0x6E  EMIT 0xC3             \
+    EMIT 0x0F  EMIT 0x6E  EMIT 0x1F             \
+    EMIT 0x0F  EMIT 0xD4  EMIT 0xCB             \
+    EMIT 0x0F  EMIT 0x6E  EMIT 0x16             \
+    EMIT 0x0F  EMIT 0xF4  EMIT 0xD0             \
+    EMIT 0x0F  EMIT 0x6E  EMIT 0x66  EMIT 0x04  \
+    EMIT 0x0F  EMIT 0xF4  EMIT 0xE0             \
+    EMIT 0x0F  EMIT 0x6E  EMIT 0x76  EMIT 0x08  \
+    EMIT 0x0F  EMIT 0xF4  EMIT 0xF0             \
+    EMIT 0x0F  EMIT 0x6E  EMIT 0x7E  EMIT 0x0C  \
+    EMIT 0x0F  EMIT 0xF4  EMIT 0xF8             \
+    EMIT 0x0F  EMIT 0xD4  EMIT 0xCA             \
+    EMIT 0x0F  EMIT 0x6E  EMIT 0x5F  EMIT 0x04  \
+    EMIT 0x0F  EMIT 0xD4  EMIT 0xDC             \
+    EMIT 0x0F  EMIT 0x6E  EMIT 0x6F  EMIT 0x08  \
+    EMIT 0x0F  EMIT 0xD4  EMIT 0xEE             \
+    EMIT 0x0F  EMIT 0x6E  EMIT 0x67  EMIT 0x0C  \
+    EMIT 0x0F  EMIT 0xD4  EMIT 0xFC             \
+    EMIT 0x0F  EMIT 0x7E  EMIT 0x0F             \
+    EMIT 0x0F  EMIT 0x6E  EMIT 0x56  EMIT 0x10  \
+    EMIT 0x0F  EMIT 0xF4  EMIT 0xD0             \
+    EMIT 0x0F  EMIT 0x73  EMIT 0xD1  EMIT 0x20  \
+    EMIT 0x0F  EMIT 0x6E  EMIT 0x66  EMIT 0x14  \
+    EMIT 0x0F  EMIT 0xF4  EMIT 0xE0             \
+    EMIT 0x0F  EMIT 0xD4  EMIT 0xCB             \
+    EMIT 0x0F  EMIT 0x6E  EMIT 0x76  EMIT 0x18  \
+    EMIT 0x0F  EMIT 0xF4  EMIT 0xF0             \
+    EMIT 0x0F  EMIT 0x7E  EMIT 0x4F  EMIT 0x04  \
+    EMIT 0x0F  EMIT 0x73  EMIT 0xD1  EMIT 0x20  \
+    EMIT 0x0F  EMIT 0x6E  EMIT 0x5E  EMIT 0x1C  \
+    EMIT 0x0F  EMIT 0xF4  EMIT 0xD8             \
+    EMIT 0x0F  EMIT 0xD4  EMIT 0xCD             \
+    EMIT 0x0F  EMIT 0x6E  EMIT 0x6F  EMIT 0x10  \
+    EMIT 0x0F  EMIT 0xD4  EMIT 0xD5             \
+    EMIT 0x0F  EMIT 0x7E  EMIT 0x4F  EMIT 0x08  \
+    EMIT 0x0F  EMIT 0x73  EMIT 0xD1  EMIT 0x20  \
+    EMIT 0x0F  EMIT 0xD4  EMIT 0xCF             \
+    EMIT 0x0F  EMIT 0x6E  EMIT 0x6F  EMIT 0x14  \
+    EMIT 0x0F  EMIT 0xD4  EMIT 0xE5             \
+    EMIT 0x0F  EMIT 0x7E  EMIT 0x4F  EMIT 0x0C  \
+    EMIT 0x0F  EMIT 0x73  EMIT 0xD1  EMIT 0x20  \
+    EMIT 0x0F  EMIT 0xD4  EMIT 0xCA             \
+    EMIT 0x0F  EMIT 0x6E  EMIT 0x6F  EMIT 0x18  \
+    EMIT 0x0F  EMIT 0xD4  EMIT 0xF5             \
+    EMIT 0x0F  EMIT 0x7E  EMIT 0x4F  EMIT 0x10  \
+    EMIT 0x0F  EMIT 0x73  EMIT 0xD1  EMIT 0x20  \
+    EMIT 0x0F  EMIT 0xD4  EMIT 0xCC             \
+    EMIT 0x0F  EMIT 0x6E  EMIT 0x6F  EMIT 0x1C  \
+    EMIT 0x0F  EMIT 0xD4  EMIT 0xDD             \
+    EMIT 0x0F  EMIT 0x7E  EMIT 0x4F  EMIT 0x14  \
+    EMIT 0x0F  EMIT 0x73  EMIT 0xD1  EMIT 0x20  \
+    EMIT 0x0F  EMIT 0xD4  EMIT 0xCE             \
+    EMIT 0x0F  EMIT 0x7E  EMIT 0x4F  EMIT 0x18  \
+    EMIT 0x0F  EMIT 0x73  EMIT 0xD1  EMIT 0x20  \
+    EMIT 0x0F  EMIT 0xD4  EMIT 0xCB             \
+    EMIT 0x0F  EMIT 0x7E  EMIT 0x4F  EMIT 0x1C  \
+    EMIT 0x83  EMIT 0xC7  EMIT 0x20             \
+    EMIT 0x83  EMIT 0xC6  EMIT 0x20             \
+    EMIT 0x0F  EMIT 0x73  EMIT 0xD1  EMIT 0x20  \
+    EMIT 0x0F  EMIT 0x7E  EMIT 0xC9
+
+#endif /* SSE2 */
+#endif /* MSVC */
+
+#if !defined(MULADDC_CORE)
+#if defined(HAVE_LONGLONG)
+
+#define MULADDC_INIT                    \
+{                                       \
+    t_dbl r;                            \
+    t_int r0, r1;
+
+#define MULADDC_CORE                    \
+    r   = *(s++) * (t_dbl) b;           \
+    r0  = r;                            \
+    r1  = r >> biL;                     \
+    r0 += c;  r1 += (r0 <  c);          \
+    r0 += *d; r1 += (r0 < *d);          \
+    c = r1; *(d++) = r0;
+
+#define MULADDC_STOP                    \
+}
+
+#else
+#define MULADDC_INIT                    \
+{                                       \
+    t_int s0, s1, b0, b1;               \
+    t_int r0, r1, rx, ry;               \
+    b0 = ( b << biH ) >> biH;           \
+    b1 = ( b >> biH );
+
+#define MULADDC_CORE                    \
+    s0 = ( *s << biH ) >> biH;          \
+    s1 = ( *s >> biH ); s++;            \
+    rx = s0 * b1; r0 = s0 * b0;         \
+    ry = s1 * b0; r1 = s1 * b1;         \
+    r1 += ( rx >> biH );                \
+    r1 += ( ry >> biH );                \
+    rx <<= biH; ry <<= biH;             \
+    r0 += rx; r1 += (r0 < rx);          \
+    r0 += ry; r1 += (r0 < ry);          \
+    r0 +=  c; r1 += (r0 <  c);          \
+    r0 += *d; r1 += (r0 < *d);          \
+    c = r1; *(d++) = r0;
+
+#define MULADDC_STOP                    \
+}
+
+#endif /* C (generic)  */
+#endif /* C (longlong) */
+
+#endif /* bn_asm.h */
diff --git a/linux-bsp/asm-study/myboot/include/common.h b/linux-bsp/asm-study/myboot/include/common.h
new file mode 100644
index 0000000..13dd894
--- /dev/null
+++ b/linux-bsp/asm-study/myboot/include/common.h
@@ -0,0 +1,52 @@
+/********************************************************************************************
+ *        File:  common.h
+ *     Version:  1.0.0
+ *   Copyright:  2011 (c) Guo Wenxue <guowenxue@gmail.com>
+ * Description:  A busy head file
+ *   ChangeLog:  1, Release initial version on "Tue Jul 12 16:43:18 CST 2011"
+ *
+ *******************************************************************************************/
+
+#ifndef __COMMON_H
+#define __COMMON_H
+
+#include <stdarg.h>
+#include <config.h>
+#include <asm/types.h>
+#include <asm/io.h>
+#include <linux/types.h>
+
+#define DEBUG
+#ifdef DEBUG
+#define dbg_print(format,args...) printf(format, ##args)
+#else
+#define dbg_print(format,args...) do{} while(0);
+#endif
+
+typedef unsigned char uchar;
+typedef volatile unsigned long vu_long;
+typedef volatile unsigned short vu_short;
+typedef volatile unsigned char vu_char;
+typedef volatile unsigned int vu_int;
+
+/*Define in board.c*/
+inline void delay(unsigned long loops);
+void init_led_beep(void);
+void turn_led_on(int led);
+void turn_led_off(int led);
+void beep(int count);
+
+void serial_init(void);
+void serial_send_byte(char c);
+int serial_is_recv_enable(void);
+int serial_recv_byte(void);
+void serial_puts(const char *s);
+long xmodem_recv(char *buf);
+
+/*Define in printf.c*/
+void * memset(void * s,int c,size_t count);
+void printf(const char *fmt, ...);
+int sprintf(char *buf, const char *fmt, ...);
+
+
+#endif
diff --git a/linux-bsp/asm-study/myboot/include/config.h b/linux-bsp/asm-study/myboot/include/config.h
new file mode 100644
index 0000000..297b4df
--- /dev/null
+++ b/linux-bsp/asm-study/myboot/include/config.h
@@ -0,0 +1,36 @@
+/********************************************************************************************
+ *        File:  start.S - Startup Code for ARM920 CPU-core
+ *     Version:  1.0.0
+ *   Copyright:  2011 (c) Guo Wenxue <guowenxue@gmail.com>
+ * Description:  Configure file for bootstrap, just like u-boot-1.3.4/include/config/s3c2440.h
+ *   ChangeLog:  1, Release initial version on "Tue Jul 12 16:43:18 CST 2011"
+ *
+ *******************************************************************************************/
+
+#ifndef __CONFIG_H
+#define __CONFIG_H
+
+#ifdef BOARD_SMDK2440
+#include <s3c2440.h>
+#define CONFIG_S3C2440
+#endif
+
+#define MDIV_405                    0x7f << 12
+#define PSDIV_405                   0x21
+
+#define CONFIG_LED_DEBUG            1
+
+#define CONFIG_SYS_MALLOC_LEN       (1024*1024)
+#define CONFIG_SYS_GBL_DATA_SIZE    128
+#define CONFIG_STACKSIZE            0x40000
+
+#define CFG_PBSIZE                  384 /* Print Buffer Size */
+
+#define CFG_MAX_NAND_DEVICE         1
+#define NAND_MAX_CHIPS              1
+#define CFG_NAND_BASE               0x4E000000
+
+#define BOOTLOADER_ENV_ADDR       0x20000   /*Bootloader enviroment start address*/
+#define LAUNCHER_NAND_ADDR        0x40000   /*Laucher save in Nandflash address*/
+
+#endif
diff --git a/linux-bsp/asm-study/myboot/include/linux/bitops.h b/linux-bsp/asm-study/myboot/include/linux/bitops.h
new file mode 100644
index 0000000..19a34db
--- /dev/null
+++ b/linux-bsp/asm-study/myboot/include/linux/bitops.h
@@ -0,0 +1,75 @@
+#ifndef _LINUX_BITOPS_H
+#define _LINUX_BITOPS_H
+
+/*
+ * ffs: find first bit set. This is defined the same way as
+ * the libc and compiler builtin ffs routines, therefore
+ * differs in spirit from the above ffz (man ffs).
+ */
+
+static inline int generic_ffs(int x)
+{
+    int r = 1;
+
+    if (!x)
+        return 0;
+    if (!(x & 0xffff))
+    {
+        x >>= 16;
+        r += 16;
+    }
+    if (!(x & 0xff))
+    {
+        x >>= 8;
+        r += 8;
+    }
+    if (!(x & 0xf))
+    {
+        x >>= 4;
+        r += 4;
+    }
+    if (!(x & 3))
+    {
+        x >>= 2;
+        r += 2;
+    }
+    if (!(x & 1))
+    {
+        x >>= 1;
+        r += 1;
+    }
+    return r;
+}
+
+/*
+ * hweightN: returns the hamming weight (i.e. the number
+ * of bits set) of a N-bit word
+ */
+
+static inline unsigned int generic_hweight32(unsigned int w)
+{
+    unsigned int res = (w & 0x55555555) + ((w >> 1) & 0x55555555);
+    res = (res & 0x33333333) + ((res >> 2) & 0x33333333);
+    res = (res & 0x0F0F0F0F) + ((res >> 4) & 0x0F0F0F0F);
+    res = (res & 0x00FF00FF) + ((res >> 8) & 0x00FF00FF);
+    return (res & 0x0000FFFF) + ((res >> 16) & 0x0000FFFF);
+}
+
+static inline unsigned int generic_hweight16(unsigned int w)
+{
+    unsigned int res = (w & 0x5555) + ((w >> 1) & 0x5555);
+    res = (res & 0x3333) + ((res >> 2) & 0x3333);
+    res = (res & 0x0F0F) + ((res >> 4) & 0x0F0F);
+    return (res & 0x00FF) + ((res >> 8) & 0x00FF);
+}
+
+static inline unsigned int generic_hweight8(unsigned int w)
+{
+    unsigned int res = (w & 0x55) + ((w >> 1) & 0x55);
+    res = (res & 0x33) + ((res >> 2) & 0x33);
+    return (res & 0x0F) + ((res >> 4) & 0x0F);
+}
+
+//#include <asm/bitops.h>
+
+#endif
diff --git a/linux-bsp/asm-study/myboot/include/linux/config.h b/linux-bsp/asm-study/myboot/include/linux/config.h
new file mode 100644
index 0000000..a0194cb
--- /dev/null
+++ b/linux-bsp/asm-study/myboot/include/linux/config.h
@@ -0,0 +1,6 @@
+#ifndef _LINUX_CONFIG_H
+#define _LINUX_CONFIG_H
+
+/* #include <linux/autoconf.h> */
+
+#endif
diff --git a/linux-bsp/asm-study/myboot/include/linux/ctype.h b/linux-bsp/asm-study/myboot/include/linux/ctype.h
new file mode 100644
index 0000000..9d7eca2
--- /dev/null
+++ b/linux-bsp/asm-study/myboot/include/linux/ctype.h
@@ -0,0 +1,54 @@
+#ifndef _LINUX_CTYPE_H
+#define _LINUX_CTYPE_H
+
+/*
+ * NOTE! This ctype does not handle EOF like the standard C
+ * library is required to.
+ */
+
+#define _U	0x01                /* upper */
+#define _L	0x02                /* lower */
+#define _D	0x04                /* digit */
+#define _C	0x08                /* cntrl */
+#define _P	0x10                /* punct */
+#define _S	0x20                /* white space (space/lf/tab) */
+#define _X	0x40                /* hex digit */
+#define _SP	0x80                /* hard space (0x20) */
+
+extern unsigned char _ctype[];
+
+#define __ismask(x) (_ctype[(int)(unsigned char)(x)])
+
+#define isalnum(c)	((__ismask(c)&(_U|_L|_D)) != 0)
+#define isalpha(c)	((__ismask(c)&(_U|_L)) != 0)
+#define iscntrl(c)	((__ismask(c)&(_C)) != 0)
+#define isdigit(c)	((__ismask(c)&(_D)) != 0)
+#define isgraph(c)	((__ismask(c)&(_P|_U|_L|_D)) != 0)
+#define islower(c)	((__ismask(c)&(_L)) != 0)
+#define isprint(c)	((__ismask(c)&(_P|_U|_L|_D|_SP)) != 0)
+#define ispunct(c)	((__ismask(c)&(_P)) != 0)
+#define isspace(c)	((__ismask(c)&(_S)) != 0)
+#define isupper(c)	((__ismask(c)&(_U)) != 0)
+#define isxdigit(c)	((__ismask(c)&(_D|_X)) != 0)
+
+#define isascii(c) (((unsigned char)(c))<=0x7f)
+#define toascii(c) (((unsigned char)(c))&0x7f)
+
+static inline unsigned char __tolower(unsigned char c)
+{
+    if (isupper(c))
+        c -= 'A' - 'a';
+    return c;
+}
+
+static inline unsigned char __toupper(unsigned char c)
+{
+    if (islower(c))
+        c -= 'a' - 'A';
+    return c;
+}
+
+#define tolower(c) __tolower(c)
+#define toupper(c) __toupper(c)
+
+#endif
diff --git a/linux-bsp/asm-study/myboot/include/linux/posix_types.h b/linux-bsp/asm-study/myboot/include/linux/posix_types.h
new file mode 100644
index 0000000..8a13ff2
--- /dev/null
+++ b/linux-bsp/asm-study/myboot/include/linux/posix_types.h
@@ -0,0 +1,49 @@
+#ifndef _LINUX_POSIX_TYPES_H
+#define _LINUX_POSIX_TYPES_H
+
+#include <linux/stddef.h>
+
+/*
+ * This allows for 1024 file descriptors: if NR_OPEN is ever grown
+ * beyond that you'll have to change this too. But 1024 fd's seem to be
+ * enough even for such "real" unices like OSF/1, so hopefully this is
+ * one limit that doesn't have to be changed [again].
+ *
+ * Note that POSIX wants the FD_CLEAR(fd,fdsetp) defines to be in
+ * <sys/time.h> (and thus <linux/time.h>) - but this is a more logical
+ * place for them. Solved by having dummy defines in <sys/time.h>.
+ */
+
+/*
+ * Those macros may have been defined in <gnu/types.h>. But we always
+ * use the ones here.
+ */
+#undef __NFDBITS
+#define __NFDBITS	(8 * sizeof(unsigned long))
+
+#undef __FD_SETSIZE
+#define __FD_SETSIZE	1024
+
+#undef __FDSET_LONGS
+#define __FDSET_LONGS	(__FD_SETSIZE/__NFDBITS)
+
+#undef __FDELT
+#define	__FDELT(d)	((d) / __NFDBITS)
+
+#undef __FDMASK
+#define	__FDMASK(d)	(1UL << ((d) % __NFDBITS))
+
+typedef struct
+{
+    unsigned long fds_bits[__FDSET_LONGS];
+} __kernel_fd_set;
+
+/* Type of a signal handler.  */
+typedef void (*__kernel_sighandler_t) (int);
+
+/* Type of a SYSV IPC key.  */
+typedef int __kernel_key_t;
+
+#include <asm/posix_types.h>
+
+#endif                          /* _LINUX_POSIX_TYPES_H */
diff --git a/linux-bsp/asm-study/myboot/include/linux/stddef.h b/linux-bsp/asm-study/myboot/include/linux/stddef.h
new file mode 100644
index 0000000..81e34c2
--- /dev/null
+++ b/linux-bsp/asm-study/myboot/include/linux/stddef.h
@@ -0,0 +1,18 @@
+#ifndef _LINUX_STDDEF_H
+#define _LINUX_STDDEF_H
+
+#undef NULL
+#if defined(__cplusplus)
+#define NULL 0
+#else
+#define NULL ((void *)0)
+#endif
+
+#ifndef _SIZE_T
+#include <linux/types.h>
+#endif
+
+#undef offsetof
+#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)
+
+#endif
diff --git a/linux-bsp/asm-study/myboot/include/linux/string.h b/linux-bsp/asm-study/myboot/include/linux/string.h
new file mode 100644
index 0000000..33d4d8d
--- /dev/null
+++ b/linux-bsp/asm-study/myboot/include/linux/string.h
@@ -0,0 +1,89 @@
+#ifndef _LINUX_STRING_H_
+#define _LINUX_STRING_H_
+
+#include <linux/types.h>        /* for size_t */
+#include <linux/stddef.h>       /* for NULL */
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+    extern char *___strtok;
+    extern char *strpbrk(const char *, const char *);
+    extern char *strtok(char *, const char *);
+    extern char *strsep(char **, const char *);
+    extern __kernel_size_t strspn(const char *, const char *);
+
+/*
+ * Include machine specific inline routines
+ */
+#include <asm/string.h>
+
+#ifndef __HAVE_ARCH_STRCPY
+    extern char *strcpy(char *, const char *);
+#endif
+#ifndef __HAVE_ARCH_STRNCPY
+    extern char *strncpy(char *, const char *, __kernel_size_t);
+#endif
+#ifndef __HAVE_ARCH_STRCAT
+    extern char *strcat(char *, const char *);
+#endif
+#ifndef __HAVE_ARCH_STRNCAT
+    extern char *strncat(char *, const char *, __kernel_size_t);
+#endif
+#ifndef __HAVE_ARCH_STRCMP
+    extern int strcmp(const char *, const char *);
+#endif
+#ifndef __HAVE_ARCH_STRNCMP
+    extern int strncmp(const char *, const char *, __kernel_size_t);
+#endif
+#if 0                           /* not used - was: #ifndef __HAVE_ARCH_STRNICMP */
+    extern int strnicmp(const char *, const char *, __kernel_size_t);
+#endif
+#ifndef __HAVE_ARCH_STRCHR
+    extern char *strchr(const char *, int);
+#endif
+#ifndef __HAVE_ARCH_STRRCHR
+    extern char *strrchr(const char *, int);
+#endif
+#ifndef __HAVE_ARCH_STRSTR
+    extern char *strstr(const char *, const char *);
+#endif
+#ifndef __HAVE_ARCH_STRLEN
+    extern __kernel_size_t strlen(const char *);
+#endif
+#ifndef __HAVE_ARCH_STRNLEN
+    extern __kernel_size_t strnlen(const char *, __kernel_size_t);
+#endif
+#ifndef __HAVE_ARCH_STRDUP
+    extern char *strdup(const char *);
+#endif
+#ifndef __HAVE_ARCH_STRSWAB
+    extern char *strswab(const char *);
+#endif
+
+#ifndef __HAVE_ARCH_MEMSET
+    extern void *memset(void *, int, __kernel_size_t);
+#endif
+#ifndef __HAVE_ARCH_MEMCPY
+    extern void *memcpy(void *, const void *, __kernel_size_t);
+#endif
+#ifndef __HAVE_ARCH_MEMMOVE
+    extern void *memmove(void *, const void *, __kernel_size_t);
+#endif
+#ifndef __HAVE_ARCH_MEMSCAN
+    extern void *memscan(void *, int, __kernel_size_t);
+#endif
+#ifndef __HAVE_ARCH_MEMCMP
+    extern int memcmp(const void *, const void *, __kernel_size_t);
+#endif
+#ifndef __HAVE_ARCH_MEMCHR
+    extern void *memchr(const void *, int, __kernel_size_t);
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif                          /* _LINUX_STRING_H_ */
diff --git a/linux-bsp/asm-study/myboot/include/linux/time.h b/linux-bsp/asm-study/myboot/include/linux/time.h
new file mode 100644
index 0000000..c00a461
--- /dev/null
+++ b/linux-bsp/asm-study/myboot/include/linux/time.h
@@ -0,0 +1,149 @@
+#ifndef _LINUX_TIME_H
+#define _LINUX_TIME_H
+
+#include <linux/types.h>
+
+#define _DEFUN(a,b,c) a(c)
+#define _CONST const
+#define _AND ,
+
+#define _REENT_ONLY
+
+#define SECSPERMIN	60L
+#define MINSPERHOUR	60L
+#define HOURSPERDAY	24L
+#define SECSPERHOUR	(SECSPERMIN * MINSPERHOUR)
+#define SECSPERDAY	(SECSPERHOUR * HOURSPERDAY)
+#define DAYSPERWEEK	7
+#define MONSPERYEAR	12
+
+#define YEAR_BASE	1900
+#define EPOCH_YEAR      1970
+#define EPOCH_WDAY      4
+
+#define isleap(y) ((((y) % 4) == 0 && ((y) % 100) != 0) || ((y) % 400) == 0)
+
+/* Used by other time functions.  */
+struct tm
+{
+    int tm_sec;                 /* Seconds.     [0-60] (1 leap second) */
+    int tm_min;                 /* Minutes.     [0-59] */
+    int tm_hour;                /* Hours.       [0-23] */
+    int tm_mday;                /* Day.         [1-31] */
+    int tm_mon;                 /* Month.       [0-11] */
+    int tm_year;                /* Year - 1900.  */
+    int tm_wday;                /* Day of week. [0-6] */
+    int tm_yday;                /* Days in year.[0-365] */
+    int tm_isdst;               /* DST.         [-1/0/1] */
+
+# ifdef __USE_BSD
+    long int tm_gmtoff;         /* Seconds east of UTC.  */
+    __const char *tm_zone;      /* Timezone abbreviation.  */
+# else
+    long int __tm_gmtoff;       /* Seconds east of UTC.  */
+    __const char *__tm_zone;    /* Timezone abbreviation.  */
+# endif
+};
+
+static inline char *_DEFUN(asctime_r, (tim_p, result), _CONST struct tm *tim_p _AND char *result)
+{
+    static _CONST char day_name[7][3] = {
+        "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"
+    };
+    static _CONST char mon_name[12][3] = {
+        "Jan", "Feb", "Mar", "Apr", "May", "Jun",
+        "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
+    };
+
+    sprintf(result, "%.3s %.3s %.2d %.2d:%.2d:%.2d %d\n",
+            day_name[tim_p->tm_wday],
+            mon_name[tim_p->tm_mon],
+            tim_p->tm_mday, tim_p->tm_hour, tim_p->tm_min, tim_p->tm_sec, 1900 + tim_p->tm_year);
+    return result;
+}
+
+static inline struct tm *_DEFUN(localtime_r, (tim_p, res),
+                                _CONST time_t * tim_p _AND struct tm *res)
+{
+    static _CONST int mon_lengths[2][MONSPERYEAR] = {
+        {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31},
+        {31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}
+    };
+
+    static _CONST int year_lengths[2] = {
+        365,
+        366
+    };
+
+    long days, rem;
+    int y;
+    int yleap;
+    _CONST int *ip;
+
+    days = ((long)*tim_p) / SECSPERDAY;
+    rem = ((long)*tim_p) % SECSPERDAY;
+    while (rem < 0)
+    {
+        rem += SECSPERDAY;
+        --days;
+    }
+    while (rem >= SECSPERDAY)
+    {
+        rem -= SECSPERDAY;
+        ++days;
+    }
+
+    /* compute hour, min, and sec */
+    res->tm_hour = (int)(rem / SECSPERHOUR);
+    rem %= SECSPERHOUR;
+    res->tm_min = (int)(rem / SECSPERMIN);
+    res->tm_sec = (int)(rem % SECSPERMIN);
+
+    /* compute day of week */
+    if ((res->tm_wday = ((EPOCH_WDAY + days) % DAYSPERWEEK)) < 0)
+        res->tm_wday += DAYSPERWEEK;
+
+    /* compute year & day of year */
+    y = EPOCH_YEAR;
+    if (days >= 0)
+    {
+        for (;;)
+        {
+            yleap = isleap(y);
+            if (days < year_lengths[yleap])
+                break;
+            y++;
+            days -= year_lengths[yleap];
+        }
+    }
+    else
+    {
+        do
+        {
+            --y;
+            yleap = isleap(y);
+            days += year_lengths[yleap];
+        }
+        while (days < 0);
+    }
+
+    res->tm_year = y - YEAR_BASE;
+    res->tm_yday = days;
+    ip = mon_lengths[yleap];
+    for (res->tm_mon = 0; days >= ip[res->tm_mon]; ++res->tm_mon)
+        days -= ip[res->tm_mon];
+    res->tm_mday = days + 1;
+
+    /* set daylight saving time flag */
+    res->tm_isdst = -1;
+
+    return (res);
+}
+
+static inline char *_DEFUN(ctime_r, (tim_p, result), _CONST time_t * tim_p _AND char *result)
+{
+    struct tm tm;
+    return asctime_r(localtime_r(tim_p, &tm), result);
+}
+
+#endif
diff --git a/linux-bsp/asm-study/myboot/include/linux/types.h b/linux-bsp/asm-study/myboot/include/linux/types.h
new file mode 100644
index 0000000..c91b15e
--- /dev/null
+++ b/linux-bsp/asm-study/myboot/include/linux/types.h
@@ -0,0 +1,131 @@
+#ifndef _LINUX_TYPES_H
+#define _LINUX_TYPES_H
+
+#ifdef	__KERNEL__
+#include <linux/config.h>
+#endif
+
+#include <linux/posix_types.h>
+#include <asm/types.h>
+
+#ifndef __KERNEL_STRICT_NAMES
+
+typedef __kernel_fd_set fd_set;
+typedef __kernel_dev_t dev_t;
+typedef __kernel_ino_t ino_t;
+typedef __kernel_mode_t mode_t;
+typedef __kernel_nlink_t nlink_t;
+typedef __kernel_off_t off_t;
+typedef __kernel_pid_t pid_t;
+typedef __kernel_daddr_t daddr_t;
+typedef __kernel_key_t key_t;
+typedef __kernel_suseconds_t suseconds_t;
+
+#ifdef __KERNEL__
+typedef __kernel_uid32_t uid_t;
+typedef __kernel_gid32_t gid_t;
+typedef __kernel_uid16_t uid16_t;
+typedef __kernel_gid16_t gid16_t;
+
+#ifdef CONFIG_UID16
+/* This is defined by include/asm-{arch}/posix_types.h */
+typedef __kernel_old_uid_t old_uid_t;
+typedef __kernel_old_gid_t old_gid_t;
+#endif                          /* CONFIG_UID16 */
+
+/* libc5 includes this file to define uid_t, thus uid_t can never change
+ * when it is included by non-kernel code
+ */
+#else
+typedef __kernel_uid_t uid_t;
+typedef __kernel_gid_t gid_t;
+#endif                          /* __KERNEL__ */
+
+#if defined(__GNUC__) && !defined(__STRICT_ANSI__)
+typedef __kernel_loff_t loff_t;
+#endif
+
+/*
+ * The following typedefs are also protected by individual ifdefs for
+ * historical reasons:
+ */
+#ifndef _SIZE_T
+#define _SIZE_T
+typedef __kernel_size_t size_t;
+#endif
+
+#ifndef _SSIZE_T
+#define _SSIZE_T
+typedef __kernel_ssize_t ssize_t;
+#endif
+
+#ifndef _PTRDIFF_T
+#define _PTRDIFF_T
+typedef __kernel_ptrdiff_t ptrdiff_t;
+#endif
+
+#ifndef _TIME_T
+#define _TIME_T
+typedef __kernel_time_t time_t;
+#endif
+
+#ifndef _CLOCK_T
+#define _CLOCK_T
+typedef __kernel_clock_t clock_t;
+#endif
+
+#ifndef _CADDR_T
+#define _CADDR_T
+typedef __kernel_caddr_t caddr_t;
+#endif
+
+/* bsd */
+typedef unsigned char u_char;
+typedef unsigned short u_short;
+typedef unsigned int u_int;
+typedef unsigned long u_long;
+
+/* sysv */
+typedef unsigned char unchar;
+typedef unsigned short ushort;
+typedef unsigned int uint;
+typedef unsigned long ulong;
+
+#ifndef __BIT_TYPES_DEFINED__
+#define __BIT_TYPES_DEFINED__
+
+typedef __u8 u_int8_t;
+typedef __s8 int8_t;
+typedef __u16 u_int16_t;
+typedef __s16 int16_t;
+typedef __u32 u_int32_t;
+typedef __s32 int32_t;
+
+#endif                          /* !(__BIT_TYPES_DEFINED__) */
+
+typedef __u8 uint8_t;
+typedef __u16 uint16_t;
+typedef __u32 uint32_t;
+
+#if defined(__GNUC__) && !defined(__STRICT_ANSI__)
+typedef __u64 uint64_t;
+typedef __u64 u_int64_t;
+typedef __s64 int64_t;
+#endif
+
+#endif                          /* __KERNEL_STRICT_NAMES */
+
+/*
+ * Below are truly Linux-specific types that should never collide with
+ * any application/library that wants linux/types.h.
+ */
+
+struct ustat
+{
+    __kernel_daddr_t f_tfree;
+    __kernel_ino_t f_tinode;
+    char f_fname[6];
+    char f_fpack[6];
+};
+
+#endif                          /* _LINUX_TYPES_H */
diff --git a/linux-bsp/asm-study/myboot/include/nand.h b/linux-bsp/asm-study/myboot/include/nand.h
new file mode 100644
index 0000000..9269296
--- /dev/null
+++ b/linux-bsp/asm-study/myboot/include/nand.h
@@ -0,0 +1,271 @@
+/*
+ *  linux/include/linux/mtd/nand.h
+ *
+ *  Copyright (c) 2000 David Woodhouse <dwmw2@infradead.org>
+ *                     Steven J. Hill <sjhill@realitydiluted.com>
+ *		       Thomas Gleixner <tglx@linutronix.de>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Info:
+ *	Contains standard defines and IDs for NAND flash devices
+ *
+ * Changelog:
+ *	See git changelog.
+ */
+#ifndef __LINUX_MTD_NAND_H
+#define __LINUX_MTD_NAND_H
+
+#include <common.h>
+#include <linux/bitops.h>
+
+#define NAND_K9F2G08      0xecda
+
+/* This constant declares the max. oobsize / page, which
+ * is supported now. If you add a chip with bigger oobsize/page
+ * adjust this accordingly.
+ */
+#define NAND_MAX_OOBSIZE	218
+#define NAND_MAX_PAGESIZE	4096
+
+/*
+ * Constants for hardware specific CLE/ALE/NCE function
+ *
+ * These are bits which can be or'ed to set/clear multiple
+ * bits in one go.
+ */
+/* Select the chip by setting nCE to low */
+#define NAND_NCE		0x01
+/* Select the command latch by setting CLE to high */
+#define NAND_CLE		0x02
+/* Select the address latch by setting ALE to high */
+#define NAND_ALE		0x04
+
+#define NAND_CTRL_CLE		(NAND_NCE | NAND_CLE)
+#define NAND_CTRL_ALE		(NAND_NCE | NAND_ALE)
+#define NAND_CTRL_CHANGE	0x80
+
+/*
+ * Standard NAND flash commands
+ */
+#define NAND_CMD_READ0		0x00        /*Page read period 1*/
+#define NAND_CMD_READSTART	0x30        /*Page read period 2, for large page*/
+#define NAND_CMD_READID		0x90        /*Read production ID*/
+#define NAND_CMD_SEQIN		0x80        /*Page write period 1*/
+#define NAND_CMD_PAGEPROG	0x10        /*Page write period 2*/
+#define NAND_CMD_ERASE1		0x60        /*Block erase period 1*/
+#define NAND_CMD_ERASE2		0xd0        /*Block erase period 2*/
+#define NAND_CMD_STATUS		0x70        /*Read status command*/
+#define NAND_CMD_RESET		0xff        /*Nandflash reset command*/
+#define NAND_CMD_READ1		1
+#define NAND_CMD_RNDOUT		0x05        /*Page random read period 1*/
+#define NAND_CMD_RNDOUTSTART	0xE0    /*Page random read period 2*/
+#define NAND_CMD_RNDIN		0x85        /*Page random write*/
+
+#define NAND_CMD_READOOB	0x50
+#define NAND_CMD_STATUS_MULTI	0x71
+
+/* Extended commands for large page devices */
+#define NAND_CMD_CACHEDPROG	0x15
+
+/* Extended commands for AG-AND device */
+/*
+ * Note: the command for NAND_CMD_DEPLETE1 is really 0x00 but
+ *       there is no way to distinguish that from NAND_CMD_READ0
+ *       until the remaining sequence of commands has been completed
+ *       so add a high order bit and mask it off in the command.
+ */
+#define NAND_CMD_DEPLETE1	0x100
+#define NAND_CMD_DEPLETE2	0x38
+#define NAND_CMD_STATUS_MULTI	0x71
+#define NAND_CMD_STATUS_ERROR	0x72
+/* multi-bank error status (banks 0-3) */
+#define NAND_CMD_STATUS_ERROR0	0x73
+#define NAND_CMD_STATUS_ERROR1	0x74
+#define NAND_CMD_STATUS_ERROR2	0x75
+#define NAND_CMD_STATUS_ERROR3	0x76
+#define NAND_CMD_STATUS_RESET	0x7f
+#define NAND_CMD_STATUS_CLEAR	0xff
+
+#define NAND_CMD_NONE		-1
+
+/* Status bits */
+#define NAND_STATUS_FAIL	0x01
+#define NAND_STATUS_FAIL_N1	0x02
+#define NAND_STATUS_TRUE_READY	0x20
+#define NAND_STATUS_READY	0x40
+#define NAND_STATUS_WP		0x80
+
+/*
+ * Constants for ECC_MODES
+ */
+typedef enum
+{
+    NAND_ECC_NONE,
+    NAND_ECC_SOFT,
+    NAND_ECC_HW,
+    NAND_ECC_HW_SYNDROME,
+    NAND_ECC_HW_OOB_FIRST,
+} nand_ecc_modes_t;
+
+/*
+ * Constants for Hardware ECC
+ */
+/* Reset Hardware ECC for read */
+#define NAND_ECC_READ		0
+/* Reset Hardware ECC for write */
+#define NAND_ECC_WRITE		1
+/* Enable Hardware ECC before syndrom is read back from flash */
+#define NAND_ECC_READSYN	2
+
+/* Bit mask for flags passed to do_nand_read_ecc */
+#define NAND_GET_DEVICE		0x80
+
+/* Option constants for bizarre disfunctionality and real
+*  features
+*/
+/* Chip can not auto increment pages */
+#define NAND_NO_AUTOINCR	0x00000001
+/* Buswitdh is 16 bit */
+#define NAND_BUSWIDTH_16	0x00000002
+/* Device supports partial programming without padding */
+#define NAND_NO_PADDING		0x00000004
+/* Chip has cache program function */
+#define NAND_CACHEPRG		0x00000008
+/* Chip has copy back function */
+#define NAND_COPYBACK		0x00000010
+/* AND Chip which has 4 banks and a confusing page / block
+ * assignment. See Renesas datasheet for further information */
+#define NAND_IS_AND		0x00000020
+/* Chip has a array of 4 pages which can be read without
+ * additional ready /busy waits */
+#define NAND_4PAGE_ARRAY	0x00000040
+/* Chip requires that BBT is periodically rewritten to prevent
+ * bits from adjacent blocks from 'leaking' in altering data.
+ * This happens with the Renesas AG-AND chips, possibly others.  */
+#define BBT_AUTO_REFRESH	0x00000080
+/* Chip does not require ready check on read. True
+ * for all large page devices, as they do not support
+ * autoincrement.*/
+#define NAND_NO_READRDY		0x00000100
+/* Chip does not allow subpage writes */
+#define NAND_NO_SUBPAGE_WRITE	0x00000200
+
+/* Options valid for Samsung large page devices */
+#define NAND_SAMSUNG_LP_OPTIONS \
+	(NAND_NO_PADDING | NAND_CACHEPRG | NAND_COPYBACK)
+
+/* Macros to identify the above */
+#define NAND_CANAUTOINCR(chip) (!(chip->options & NAND_NO_AUTOINCR))
+#define NAND_MUST_PAD(chip) (!(chip->options & NAND_NO_PADDING))
+#define NAND_HAS_CACHEPROG(chip) ((chip->options & NAND_CACHEPRG))
+#define NAND_HAS_COPYBACK(chip) ((chip->options & NAND_COPYBACK))
+/* Large page NAND with SOFT_ECC should support subpage reads */
+#define NAND_SUBPAGE_READ(chip) ((chip->ecc.mode == NAND_ECC_SOFT) \
+					&& (chip->page_shift > 9))
+
+/* Mask to zero out the chip options, which come from the id table */
+#define NAND_CHIPOPTIONS_MSK	(0x0000ffff & ~NAND_NO_AUTOINCR)
+
+/* Non chip related options */
+/* Use a flash based bad block table. This option is passed to the
+ * default bad block table function. */
+#define NAND_USE_FLASH_BBT	0x00010000
+/* This option skips the bbt scan during initialization. */
+#define NAND_SKIP_BBTSCAN	0x00020000
+/* This option is defined if the board driver allocates its own buffers
+   (e.g. because it needs them DMA-coherent */
+#define NAND_OWN_BUFFERS	0x00040000
+/* Options set by nand scan */
+/* bbt has already been read */
+#define NAND_BBT_SCANNED	0x40000000
+/* Nand scan has allocated controller struct */
+#define NAND_CONTROLLER_ALLOC	0x80000000
+
+/* Cell info constants */
+#define NAND_CI_CHIPNR_MSK	0x03
+#define NAND_CI_CELLTYPE_MSK	0x0C
+
+/*
+ * NAND Flash Manufacturer ID Codes
+ */
+#define NAND_MFR_TOSHIBA	0x98
+#define NAND_MFR_SAMSUNG	0xec
+#define NAND_MFR_FUJITSU	0x04
+#define NAND_MFR_NATIONAL	0x8f
+#define NAND_MFR_RENESAS	0x07
+#define NAND_MFR_STMICRO	0x20
+#define NAND_MFR_HYNIX		0xad
+#define NAND_MFR_MICRON		0x2c
+#define NAND_MFR_AMD		0x01
+
+/*
+* Constants for oob configuration
+*/
+#define NAND_SMALL_BADBLOCK_POS		5
+#define NAND_LARGE_BADBLOCK_POS		0
+
+
+#if defined(CONFIG_S3C2410)
+#define REG_NFCONF      __REGi(ELFIN_NAND_BASE + 0x0)
+#define REG_NFCMD       __REGb(ELFIN_NAND_BASE + 0x4)
+#define REG_NFADDR      __REGb(ELFIN_NAND_BASE + 0x8)
+#define REG_NFDATA      __REGb(ELFIN_NAND_BASE + 0xc)
+#define REG_NFSTAT      __REGb(ELFIN_NAND_BASE + 0x10)
+#define NFSTAT_BUSY 1
+#define nand_select()   (REG_NFCONF &= ~0x800)   /*Clear bit 11*/
+#define nand_deselect() (REG_NFCONF |= 0x800)
+#define nand_clear_RnB()    do {} while (0)  
+#define nand_detect_RnB()    do {} while (0)  
+#define nand_wait_RnB()    do {} while (0)  
+
+#elif defined(CONFIG_S3C2440) || defined(CONFIG_S3C2442)
+
+#define REG_NFCONF      __REGi(ELFIN_NAND_BASE + 0x0)
+#define REG_NFCONT      __REGi(ELFIN_NAND_BASE + 0x4)
+#define REG_NFCMD       __REGb(ELFIN_NAND_BASE + 0x8)
+#define REG_NFADDR      __REGb(ELFIN_NAND_BASE + 0xc)
+#define REG_NFDATA      __REGb(ELFIN_NAND_BASE + 0x10)
+#define REG_NFDATA16    __REGw(ELFIN_NAND_BASE + 0x10)
+#define REG_NFSTAT      __REGb(ELFIN_NAND_BASE + 0x20)
+#define NFSTAT_BUSY 1
+#define nand_select()   (REG_NFCONT &= ~(1 << 1))
+#define nand_deselect() (REG_NFCONT |= (1 << 1))
+#define nand_clear_RnB()    (REG_NFSTAT |= (1 << 2))
+#define nand_detect_RnB()   {while(!(REG_NFSTAT&(1<<2)));}   /*Wait Read & Busy signal goto high(not busy)*/ 
+#define nand_wait_RnB()   {while(!(REG_NFSTAT&(1<<0)));}   /*Wait nand flash not busy, wait bit[0] goes to 1*/ 
+
+#endif
+
+#define SKIP_BAD_BLOCK       1
+#define NOT_SKIP_BAD_BLOCK   0
+
+struct boot_nand_t
+{
+    int page_size; 
+    int spare_size; 
+    int block_size; 
+    int block_num;
+    int bad_block_offset; 
+    int id;
+    //  unsigned long size;
+};
+
+int nand_init(struct boot_nand_t *nand);
+int nand_read_page(struct boot_nand_t *nand, ulong page_num, ulong offset, char *data, ulong size);
+int nand_write_page(struct boot_nand_t *nand, ulong page_num, ulong offset, char *data, ulong size);
+int is_bad_block(struct boot_nand_t *nand, ulong addr);
+int mark_bad_block(struct boot_nand_t *nand, ulong addr);
+int nand_erase_block(struct boot_nand_t *nand, ulong block_num);
+int nand_erase(struct boot_nand_t *nand, ulong start_addr, ulong size, int skip_bad);
+void nand_scrub(struct boot_nand_t *nand);
+int nand_read_spare(struct boot_nand_t *nand, ulong page_addr, int size, char *buf);
+int nand_write_spare(struct boot_nand_t *nand, ulong page_addr, int size, char *buf);
+int nand_read(struct boot_nand_t *nand, ulong start_addr, ulong size, char *buf);
+int nand_write(struct boot_nand_t *nand, ulong start_addr, ulong size, char *buf);
+
+
+
+#endif                          /* __LINUX_MTD_NAND_H */
diff --git a/linux-bsp/asm-study/myboot/include/rsa.h b/linux-bsp/asm-study/myboot/include/rsa.h
new file mode 100644
index 0000000..703ac7d
--- /dev/null
+++ b/linux-bsp/asm-study/myboot/include/rsa.h
@@ -0,0 +1,208 @@
+/**
+ * \file rsa.h
+ */
+#ifndef _RSA_H
+#define _RSA_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "bignum.h"
+
+#define ERR_RSA_BAD_INPUT_DATA                  0x0300
+#define ERR_RSA_INVALID_PADDING                 0x0310
+#define ERR_RSA_KEY_GEN_FAILED                  0x0320
+#define ERR_RSA_KEY_CHK_FAILED                  0x0330
+#define ERR_RSA_PUBLIC_FAILED                   0x0340
+#define ERR_RSA_PRIVATE_FAILED                  0x0350
+#define ERR_RSA_VERIFY_FAILED                   0x0360
+
+/*
+ * PKCS#1 stuff
+ */
+#define RSA_RAW             0
+#define RSA_MD2             2
+#define RSA_MD4             3
+#define RSA_MD5             4
+#define RSA_SHA1            5
+
+#define RSA_SIGN            0x01
+#define RSA_CRYPT           0x02
+
+/*
+ * DigestInfo ::= SEQUENCE {
+ *   digestAlgorithm DigestAlgorithmIdentifier,
+ *   digest Digest }
+ *
+ * DigestAlgorithmIdentifier ::= AlgorithmIdentifier
+ *
+ * Digest ::= OCTET STRING
+ */
+#define ASN1_HASH_MDX                       \
+    "\x30\x20\x30\x0C\x06\x08\x2A\x86\x48"  \
+    "\x86\xF7\x0D\x02\x00\x05\x00\x04\x10"
+
+#define ASN1_HASH_SHA1                      \
+    "\x30\x21\x30\x09\x06\x05\x2B\x0E\x03"  \
+    "\x02\x1A\x05\x00\x04\x14"
+
+typedef struct
+{
+    int ver;    /*!<  should be 0       */
+    int len;    /*!<  size(N) in chars  */
+    mpi N;      /*!<  public modulus    */
+    mpi E;      /*!<  public exponent   */
+    mpi D;      /*!<  private exponent  */
+
+    mpi P;      /*!<  1st prime factor  */
+    mpi Q;      /*!<  2nd prime factor  */
+    mpi DP;     /*!<  D mod (P - 1)     */
+    mpi DQ;     /*!<  D mod (Q - 1)     */
+    mpi QP;     /*!<  inverse of Q % P  */
+
+    mpi RN;     /*!<  cached R^2 mod N  */
+    mpi RP;     /*!<  cached R^2 mod P  */
+    mpi RQ;     /*!<  cached R^2 mod Q  */
+}
+rsa_context;
+
+/**
+ * \brief          Generate an RSA keypair
+ *
+ * \param ctx      RSA context to be initialized
+ * \param nbits    size of the public key in bits
+ * \param exponent public exponent (e.g., 65537)
+ * \param rng_f    points to the RNG function
+ * \param rng_d    points to the RNG data 
+ *
+ * \return         0 if successful, or an ERR_RSA_XXX error code
+ */
+int rsa_gen_key( rsa_context *ctx, int nbits, int exponent,
+                 int (*rng_f)(void *), void *rng_d );
+
+/**
+ * \brief          Perform an RSA public key operation
+ *
+ * \return         0 if successful, or an ERR_RSA_XXX error code
+ *
+ * \note           This function does not take care of message
+ *                 padding: both ilen and olen must be equal to
+ *                 the modulus size (ctx->len). Also, be sure
+ *                 to set input[0] = 0.
+ */
+int rsa_public( rsa_context   *ctx,
+                unsigned char *input,  int ilen,
+                unsigned char *output, int *olen );
+
+/**
+ * \brief          Perform an RSA private key operation
+ *
+ * \return         0 if successful, or an ERR_RSA_XXX error code
+ *
+ * \note           This function does not take care of message
+ *                 padding: both ilen and olen must be equal to
+ *                 the modulus size (ctx->len). Also, be sure
+ *                 to set input[0] = 0.
+ */
+int rsa_private( rsa_context   *ctx,
+                 unsigned char *input,  int ilen,
+                 unsigned char *output, int *olen );
+
+/**
+ * \brief          Return 0 if the public key is valid,
+ *                 or ERR_RSA_KEY_CHECK_FAILED
+ */
+int rsa_check_pubkey( rsa_context *ctx );
+
+/**
+ * \brief          Return 0 if the private key is valid,
+ *                 or ERR_RSA_KEY_CHECK_FAILED
+ */
+int rsa_check_privkey( rsa_context *ctx );
+
+/**
+ * \brief          Add the PKCS#1 v1.5 padding and do a public RSA
+ *
+ * \param ctx      RSA context
+ * \param input    buffer holding the data to be encrypted
+ * \param ilen     length of the plaintext; cannot be longer
+ *                 than the modulus, minus 3+8 for padding
+ * \param output   buffer that will hold the ciphertext
+ * \param olen     must be the same as the modulus size
+ *                 (for example, 128 if RSA-1024 is used)
+ *
+ * \return         0 if successful, or an ERR_RSA_XXX error code
+ */
+int rsa_pkcs1_encrypt( rsa_context   *ctx,
+                       unsigned char *input,  int ilen,
+                       unsigned char *output, int *olen );
+
+/**
+ * \brief          Do a private RSA, removes the PKCS#1 v1.5 padding
+ *
+ * \param ctx      RSA context
+ * \param input    buffer holding the encrypted data
+ * \param ilen     must be the same as the modulus size
+ * \param output   buffer that will hold the plaintext
+ * \param olen     size of output buffer, will be updated
+ *                 to contain the length of the plaintext
+ *
+ * \return         0 if successful, or an ERR_RSA_XXX error code
+ */
+int rsa_pkcs1_decrypt( rsa_context   *ctx,
+                       unsigned char *input,  int  ilen,
+                       unsigned char *output, int *olen );
+
+/**
+ * \brief          Perform a private RSA to sign a message digest
+ *
+ * \param ctx      RSA context
+ * \param alg_id   RSA_RAW, RSA_MD2/4/5 or RSA_SHA1
+ * \param hash     buffer holding the message digest
+ * \param hashlen  message digest length
+ * \param sig      buffer that will hold the ciphertext
+ * \param siglen   must be the same as the modulus size
+ *                 (for example, 128 if RSA-1024 is used)
+ *
+ * \return         0 if the signing operation was successful,
+ *                 or an ERR_RSA_XXX error code
+ */
+int rsa_pkcs1_sign( rsa_context   *ctx,  int alg_id,
+                    unsigned char *hash, int hashlen,
+                    unsigned char *sig,  int siglen );
+
+/**
+ * \brief          Perform a public RSA and check the message digest
+ *
+ * \param ctx      points to an RSA public key
+ * \param alg_id   RSA_RAW, RSA_MD2/4/5 or RSA_SHA1
+ * \param hash     buffer holding the message digest
+ * \param hashlen  message digest length
+ * \param sig      buffer holding the ciphertext
+ * \param siglen   must be the same as the modulus size
+ *
+ * \return         0 if the verify operation was successful,
+ *                 or an ERR_RSA_XXX error code
+ */
+int rsa_pkcs1_verify( rsa_context   *ctx,  int alg_id,
+                      unsigned char *hash, int hashlen,
+                      unsigned char *sig,  int siglen );
+
+/**
+ * \brief          Free the components of an RSA key
+ */
+void rsa_free( rsa_context *ctx );
+
+/**
+ * \brief          Checkup routine
+ *
+ * \return         0 if successful, or 1 if the test failed
+ */
+int rsa_self_test( void );
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/linux-bsp/asm-study/myboot/include/s3c2440.h b/linux-bsp/asm-study/myboot/include/s3c2440.h
new file mode 100644
index 0000000..308dc25
--- /dev/null
+++ b/linux-bsp/asm-study/myboot/include/s3c2440.h
@@ -0,0 +1,674 @@
+/*
+ * (C) Copyright 2003
+ * David M�ller ELSOFT AG Switzerland. d.mueller@elsoft.ch
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+/************************************************
+ * NAME	    : s3c2440.h
+ *
+ * Based on S3C2440A User's manual Rev 1.1
+ ************************************************/
+
+#ifndef __S3C2440_H__
+#define __S3C2440_H__
+
+/*This is debug on FL2440 board*/
+#define BEEP     0              /*Buzzer use GPB0 */
+#define LED0     5              /*LED0 use GPB5 */
+#define LED1     6              /*LED1 use GPB6 */
+#define LED2     8              /*LED2 use GPB8 */
+#define LED3     10             /*LED3 use GPB10 */
+/*FL2440 LED & Beep define end*/
+
+#define S3C24X0_UART_CHANNELS	3
+#define S3C24X0_SPI_CHANNELS	2
+
+#include <asm/hardware.h>
+
+#ifndef __ASSEMBLY__
+typedef enum
+{
+    S3C24X0_UART0,
+    S3C24X0_UART1,
+} S3C24X0_UARTS_NR;
+
+#include <s3c24x0.h>
+#endif
+
+#define ROM_BASE0		0x00000000  /* base address of rom bank 0 */
+#define ROM_BASE1		0x04000000  /* base address of rom bank 1 */
+#define DRAM_BASE0		0x30000000  /* base address of dram bank 0 */
+#define DRAM_BASE1		0x00000000  /* base address of dram bank 1 */
+
+/* S3C2440 only supports 512 Byte HW ECC */
+#define S3C2410_ECCSIZE		512
+#define S3C2410_ECCBYTES	3
+
+/* S3C2440 device base addresses */
+#define ELFIN_DMA_BASE		0x4b000000
+#define ELFIN_USB_DEVICE_BASE	0x44a00000
+#define ELFIN_I2C_BASE		0x54000000
+#define ELFIN_I2S_BASE		0x55000000
+#define ELFIN_ADC_BASE		0x58000000
+#define ELFIN_SPI_BASE		0x59000000
+#define ELFIN_SDI_BASE		0x5A000000
+
+/*
+ * Memory controller
+ */
+
+#define ELFIN_MEM_CON_BASE	0x48000000
+
+#define BWSCON_OFFSET		0x00
+#define BANKCON0_OFFSET		0x04
+#define BANKCON1_OFFSET		0x08
+#define BANKCON2_OFFSET		0x0c
+#define BANKCON3_OFFSET		0x10
+#define BANKCON4_OFFSET		0x14
+#define BANKCON5_OFFSET		0x18
+#define BANKCON6_OFFSET		0x1c
+#define BANKCON7_OFFSET		0x20
+#define REFRESH_OFFSET		0x24
+#define BANKSIZE_OFFSET		0x28
+#define MRSRB6_OFFSET		0x2c
+#define MRSRB7_OFFSET		0x30
+
+#define BWSCON_REG		__REG(0x48000000)
+#define BANKCON0_REG		__REG(0x48000004)
+#define BANKCON1_REG		__REG(0x48000008)
+#define BANKCON2_REG		__REG(0x4800000c)
+#define BANKCON3_REG		__REG(0x48000010)
+#define BANKCON4_REG		__REG(0x48000014)
+#define BANKCON5_REG		__REG(0x48000018)
+#define BANKCON6_REG		__REG(0x4800001c)
+#define BANKCON7_REG		__REG(0x48000020)
+#define REFRESH_REG		__REG(0x48000024)
+#define BANKSIZE_REG		__REG(0x48000028)
+#define MRSRB6_REG		__REG(0x4800002c)
+#define MRSRB7_REG		__REG(0x48000030)
+
+/*
+ * USB Host Controller
+ */
+#define ELFIN_USB_HOST_BASE	0x49000000
+
+#define HcRevision_OFFSET	0x00
+#define HcControl_OFFSET	0x04
+#define HcCommonStatus_OFFSET	0x08
+#define HcIntStatus_OFFSET	0x0c
+#define HcIntEnable_OFFSET	0x10
+#define HcIntDisable_OFFSET	0x14
+#define HcHCCA_OFFSET		0x18
+#define HcPerdCurED_OFFSET	0x1c
+#define HcCtrlHeadED_OFFSET	0x20
+#define HcCtrlCurED_OFFSET	0x24
+#define HcBulkHeadED_OFFSET	0x28
+#define HcBulkCurED_OFFSET	0x2c
+#define HcDoneHead_OFFSET	0x30
+#define HcRmInterval_OFFSET	0x34
+#define HcFmRemain_OFFSET	0x38
+#define HcFmNumber_OFFSET	0x3c
+#define HcPerdStart_OFFSET	0x40
+#define HcLSThres_OFFSET	0x44
+#define HcRhDescA_OFFSET	0x48
+#define HcRhDescB_OFFSET	0x4c
+#define HcRhStatus_OFFSET	0x50
+#define HcRhPortSts1_OFFSET	0x54
+#define HcRhPortSts2_OFFSET	0x58
+
+#define HcRevision_REG		__REG(0x49000000)
+#define HcControl_REG		__REG(0x49000004)
+#define HcCommonStatus_REG	__REG(0x49000008)
+#define HcIntStatus_REG		__REG(0x4900000c)
+#define HcIntEnable_REG		__REG(0x49000010)
+#define HcIntDisable_REG	__REG(0x49000014)
+#define HcHCCA_REG		__REG(0x49000018)
+#define HcPerdCurED_REG		__REG(0x4900001c)
+#define HcCtrlHeadED_REG	__REG(0x49000020)
+#define HcCtrlCurED_REG		__REG(0x49000024)
+#define HcBulkHeadED_REG	__REG(0x49000028)
+#define HcBulkCurED_REG		__REG(0x4900002c)
+#define HcDoneHead_REG		__REG(0x49000030)
+#define HcRmInterval_REG	__REG(0x49000034)
+#define HcFmRemain_REG		__REG(0x49000038)
+#define HcFmNumber_REG		__REG(0x4900003c)
+#define HcPerdStart_REG		__REG(0x49000040)
+#define HcLSThres_REG		__REG(0x49000044)
+#define HcRhDescA_REG		__REG(0x49000048)
+#define HcRhDescB_REG		__REG(0x4900004c)
+#define HcRhStatus_REG		__REG(0x49000050)
+#define HcRhPortSts1_REG	__REG(0x49000054)
+#define HcRhPortSts2_REG	__REG(0x49000058)
+
+/*
+ * Interrupt
+ */
+#define ELFIN_INTERRUPT_BASE	0x4a000000
+
+#define SRCPND_OFFSET		0x00
+#define INTMOD_OFFSET		0x04
+#define INTMSK_OFFSET		0x08
+#define PRIORITY_OFFSET		0x0c
+#define INTPND_OFFSET		0x10
+#define INTOFFSET_OFFSET	0x14
+#define SUBSRCPND_OFFSET	0x18
+#define INTSUBMSK_OFFSET	0x1c
+
+#define SRCPND_REG		__REG(0x4a000000)
+#define INTMOD_REG		__REG(0x4a000004)
+#define INTMSK_REG		__REG(0x4a000008)
+#define PRIORITY_REG		__REG(0x4a00000c)
+#define INTPND_REG		__REG(0x4a000010)
+#define INTOFFSET_REG		__REG(0x4a000014)
+#define SUBSRCPND_REG		__REG(0x4a000018)
+#define INTSUBMSK_REG		__REG(0x4a00001C)
+
+/*
+ * Clock and power management
+ */
+
+#define ELFIN_CLOCK_POWER_BASE	0x4c000000
+
+#define LOCKTIME_OFFSET		0x00
+#define MPLLCON_OFFSET		0x04
+#define UPLLCON_OFFSET		0x08
+#define CLKCON_OFFSET		0x0c
+#define CLKSLOW_OFFSET		0x10
+#define CLKDIVN_OFFSET		0x14
+#define CAMDIVN_OFFSET		0x18
+
+#define LOCKTIME_REG		__REG(0x4c000000)
+#define MPLLCON_REG		__REG(0x4c000004)
+#define UPLLCON_REG		__REG(0x4c000008)
+#define CLKCON_REG		__REG(0x4c00000c)
+#define CLKSLOW_REG		__REG(0x4c000010)
+#define CLKDIVN_REG		__REG(0x4c000014)
+#define CAMDIVN_REG		__REG(0x4c000018)
+
+/*
+ * LCD Controller
+ */
+#define ELFIN_LCD_BASE		0x4d000000
+
+/*
+ * GPIO
+ */
+
+#define ELFIN_GPIO_BASE	0x56000000
+
+#define GPACON_OFFSET		0x00
+#define GPADAT_OFFSET		0x04
+#define GPAPU_OFFSET		0x08
+#define GPASLPCON_OFFSET	0x0C
+#define GPABON_OFFSET		0x10
+#define GPBDAT_OFFSET		0x14
+#define GPBPU_OFFSET		0x18
+#define GPBSLPCON_OFFSET	0x1C
+#define GPCCON_OFFSET		0x20
+#define GPCDAT_OFFSET		0x24
+#define GPCPU_OFFSET		0x28
+#define GPCSLPCON_OFFSET	0x2C
+#define GPDCON_OFFSET		0x30
+#define GPDDAT_OFFSET		0x34
+#define GPDPU_OFFSET		0x38
+#define GPECON_OFFSET		0x40
+#define GPEDAT_OFFSET		0x44
+#define GPEPU_OFFSET		0x48
+#define GPESLPCON_OFFSET	0x4C
+#define GPFCON_OFFSET		0x50
+#define GPFDAT_OFFSET		0x54
+#define GPFPU_OFFSET		0x58
+#define GPFSLPCON_OFFSET	0x5C
+#define GPGCON_OFFSET		0x60
+#define GPGDAT_OFFSET		0x64
+#define GPGPU_OFFSET		0x68
+#define GPGSLPCON_OFFSET	0x6C
+#define GPHCON_OFFSET		0x70
+#define GPHDAT_OFFSET		0x74
+#define GPHPU_OFFSET		0x78
+#define GPHSLPCON_OFFSET	0x7C
+#define GPICON_OFFSET		0x80
+#define GPIDAT_OFFSET		0x84
+#define GPIPU_OFFSET		0x88
+#define GPISLPCON_OFFSET	0x8C
+#define GPJCON_OFFSET		0x90
+#define GPJDAT_OFFSET		0x94
+#define GPJPU_OFFSET		0x98
+#define SPCON_OFFSET		0x9C
+#define GPKCON_OFFSET		0xA0
+#define GPKDAT_OFFSET		0xA4
+#define GPKPU_OFFSET		0xA8
+#define GPKSLPCON_OFFSET	0xAC
+#define EINTCON0_OFFSET		0xB0
+#define EINTCON1_OFFSET		0xB4
+#define EINTFLT0_OFFSET		0xB8
+#define EINTFLT1_OFFSET		0xBC
+#define EINTMASK_OFFSET		0xC0
+#define EINTPEND_OFFSET		0xC4
+#define DSPGPSLP_OFFSET		0xC8
+#define MEM0CONSTOP_OFFSET	0xD0
+#define MEM1CONSTOP_OFFSET	0xD4
+#define MEM2CONSTOP_OFFSET	0xD8
+#define MEM0CONSLP_OFFSET	0xE0
+#define MEM1CONSLP_OFFSET	0xE4
+#define MEM2CONSLP_OFFSET	0xE8
+#define SPCONSLP_OFFSET		0xEC
+#define SLPEN_OFFSET		0xF0
+#define MEM0DRVCON_OFFSET	0xF4
+#define MEM1DRVCON_OFFSET	0xF8
+#define MEM2DRVCON_OFFSET	0xFC
+
+#define GPACON_REG		__REG(0x44800000)
+#define GPADAT_REG		__REG(0x44800004)
+#define GPAPU_REG		__REG(0x44800008)
+#define GPASLPCON_REG		__REG(0x4480000C)
+#define GPABON_REG		__REG(0x44800010)
+#define GPBDAT_REG		__REG(0x44800014)
+#define GPBPU_REG		__REG(0x44800018)
+#define GPBSLPCON_REG		__REG(0x4480001C)
+#define GPCCON_REG		__REG(0x44800020)
+#define GPCDAT_REG		__REG(0x44800024)
+#define GPCPU_REG		__REG(0x44800028)
+#define GPCSLPCON_REG		__REG(0x4480002C)
+#define GPDCON_REG		__REG(0x44800030)
+#define GPDDAT_REG		__REG(0x44800034)
+#define GPDPU_REG		__REG(0x44800038)
+#define GPECON_REG		__REG(0x44800040)
+#define GPEDAT_REG		__REG(0x44800044)
+#define GPEPU_REG		__REG(0x44800048)
+#define GPESLPCON_REG		__REG(0x4480004C)
+#define GPFCON_REG		__REG(0x44800050)
+#define GPFDAT_REG		__REG(0x44800054)
+#define GPFPU_REG		__REG(0x44800058)
+#define GPFSLPCON_REG		__REG(0x4480005C)
+#define GPGCON_REG		__REG(0x44800060)
+#define GPGDAT_REG		__REG(0x44800064)
+#define GPGPU_REG		__REG(0x44800068)
+#define GPGSLPCON_REG		__REG(0x4480006C)
+#define GPHCON_REG		__REG(0x44800070)
+#define GPHDAT_REG		__REG(0x44800074)
+#define GPHPU_REG		__REG(0x44800078)
+#define GPHSLPCON_REG		__REG(0x4480007C)
+#define GPICON_REG		__REG(0x44800080)
+#define GPIDAT_REG		__REG(0x44800084)
+#define GPIPU_REG		__REG(0x44800088)
+#define GPISLPCON_REG		__REG(0x4480008C)
+#define GPJCON_REG		__REG(0x44800090)
+#define GPJDAT_REG		__REG(0x44800094)
+#define GPJPU_REG		__REG(0x44800098)
+#define SPCON_REG		__REG(0x4480009C)
+#define GPKCON_REG		__REG(0x448000A0)
+#define GPKDAT_REG		__REG(0x448000A4)
+#define GPKPU_REG		__REG(0x448000A8)
+#define GPKSLPCON_REG		__REG(0x448000AC)
+#define EINTCON0_REG		__REG(0x448000B0)
+#define EINTCON1_REG		__REG(0x448000B4)
+#define EINTFLT0_REG		__REG(0x448000B8)
+#define EINTFLT1_REG		__REG(0x448000BC)
+#define EINTMASK_REG		__REG(0x448000C0)
+#define EINTPEND_REG		__REG(0x448000C4)
+#define DSPGPSLP_REG		__REG(0x448000C8)
+#define MEM0CONSTOP_REG		__REG(0x448000D0)
+#define MEM1CONSTOP_REG		__REG(0x448000D4)
+#define MEM2CONSTOP_REG		__REG(0x448000D8)
+#define MEM0CONSLP_REG		__REG(0x448000E0)
+#define MEM1CONSLP_REG		__REG(0x448000E4)
+#define MEM2CONSLP_REG		__REG(0x448000E8)
+#define SPCONSLP_REG		__REG(0x448000EC)
+#define SLPEN_REG		__REG(0x448000F0)
+#define MEM0DRVCON_REG		__REG(0x448000F4)
+#define MEM1DRVCON_REG		__REG(0x448000F8)
+#define MEM2DRVCON_REG		__REG(0x448000FC)
+
+/*
+ * Nand flash controller
+ */
+
+#define ELFIN_NAND_BASE	0x4e000000
+
+#define NFCONF_OFFSET		0x00
+#define NFCONT_OFFSET		0x04
+#define NFCMMD_OFFSET		0x08
+#define NFADDR_OFFSET		0x0c
+#define NFDATA_OFFSET		0x10
+#define NFMECCD0_OFFSET		0x14
+#define NFMECCD1_OFFSET		0x18
+#define NFSECCD_OFFSET		0x1c
+#define NFSTAT_OFFSET		0x20
+#define NFESTAT0_OFFSET		0x24
+#define NFESTAT1_OFFSET		0x28
+#define NFMECC0_OFFSET		0x2c
+#define NFMECC1_OFFSET		0x30
+#define NFSECC_OFFSET		0x34
+#define NFSBLK_OFFSET		0x38
+#define NFEBLK_OFFSET		0x3c
+
+#define NFCONF		(0x4e000000)
+#define NFCONT		(0x4e000004)
+#define NFCMMD		(0x4e000008)
+#define NFADDR		(0x4e00000C)
+#define NFDATA		(0x4e000010)
+#define NFMECCDATA0	(0x4e000014)
+#define NFMECCDATA1	(0x4e000018)
+#define NFSECCDATA	(0x4e00001c)
+#define NFSTAT		(0x4e000020)
+#define NFESTAT0	(0x4e000024)
+#define NFESTAT1	(0x4e000028)
+#define NFMECC0		(0x4e00002C)
+#define NFMECC1		(0x4e000030)
+#define NFSECC		(0x4e00003c)
+
+#define NFCONF_REG		__REG(0x4e000000)
+#define NFCONT_REG		__REG(0x4e000004)
+#define NFCMD_REG		__REGb(0x4e000008)
+#define NFADDR_REG		__REGb(0x4e00000C)
+#define NFDATA8_REG		__REGb(0x4e000010)
+#define NFDATA16_REG		__REGw(0x4e000010)
+#define NFDATA32_REG		__REG(0x4e000010)
+#define NFSTAT_REG		__REG(0x4e000020)
+
+#define NFCONT_WP		(1<<12)
+#define NFCONT_SECCLOCK		(1<<6)
+#define NFCONT_MECCLOCK		(1<<5)
+#define NFCONT_INITECC		(1<<4)
+#define NFCONT_CS_ALT		(1<<1)
+#define NFCONT_CS		(1<<1)
+#define NFSTAT_RnB		(1<<0)
+
+/*
+ * Watchdog timer
+ */
+
+#define ELFIN_WATCHDOG_BASE	0x53000000
+
+#define WTCON_OFFSET		0x00
+#define WTDAT_OFFSET		0x04
+#define WTCNT_OFFSET		0x08
+
+#define WTCON_REG		__REG(0x53000000)
+#define WTDAT_REG		__REG(0x53000004)
+#define WTCNT_REG		__REG(0x53000008)
+
+/*
+ * UART
+ */
+#define ELFIN_UART_BASE		0x50000000
+
+#define ULCON0_OFFSET		0x00
+#define UCON0_OFFSET		0x04
+#define UFCON0_OFFSET		0x08
+#define UMCON0_OFFSET		0x0C
+#define UTRSTAT0_OFFSET		0x10
+#define UERSTAT0_OFFSET		0x14
+#define UFSTAT0_OFFSET		0x18
+#define UMSTAT0_OFFSET		0x1C
+#define UTXH0_OFFSET		0x20
+#define URXH0_OFFSET		0x24
+#define UBRDIV0_OFFSET		0x28
+
+#define ULCON0_REG		__REG(0x50000000)
+#define UCON0_REG		__REG(0x50000004)
+#define UFCON0_REG		__REG(0x50000008)
+#define UMCON0_REG		__REG(0x5000000C)
+#define UTRSTAT0_REG		__REG(0x50000010)
+#define UERSTAT0_REG		__REG(0x50000014)
+#define UFSTAT0_REG		__REG(0x50000018)
+#define UMSTAT0_REG		__REG(0x5000001C)
+#define UTXH0_REG		__REG(0x50000020)
+#define URXH0_REG		__REG(0x50000024)
+#define UBRDIV0_REG		__REG(0x50000028)
+
+#define ULCON1_REG		__REG(0x50004000)
+#define UCON1_REG		__REG(0x50004004)
+#define UFCON1_REG		__REG(0x50004008)
+#define UMCON1_REG		__REG(0x5000400C)
+#define UTRSTAT1_REG		__REG(0x50004010)
+#define UERSTAT1_REG		__REG(0x50004014)
+#define UFSTAT1_REG		__REG(0x50004018)
+#define UMSTAT1_REG		__REG(0x5000401C)
+#define UTXH1_REG		__REG(0x50004020)
+#define URXH1_REG		__REG(0x50004024)
+#define UBRDIV1_REG		__REG(0x50004028)
+
+#define ULCON2_REG		__REG(0x50008000)
+#define UCON2_REG		__REG(0x50008004)
+#define UFCON2_REG		__REG(0x50008008)
+#define UMCON2_REG		__REG(0x5000800C)
+#define UTRSTAT2_REG		__REG(0x50008010)
+#define UERSTAT2_REG		__REG(0x50008014)
+#define UFSTAT2_REG		__REG(0x50008018)
+#define UMSTAT2_REG		__REG(0x5000801C)
+#define UTXH2_REG		__REG(0x50008020)
+#define URXH2_REG		__REG(0x50008024)
+#define UBRDIV2_REG		__REG(0x50008028)
+
+#define UTRSTAT_TX_EMPTY	(1 << 2)
+#define UTRSTAT_RX_READY	(1 << 0)
+#define UART_ERR_MASK		0xF
+
+/*
+ * PWM timer
+ */
+#define ELFIN_TIMER_BASE	0x51000000
+
+#define TCFG0_REG		__REG(0x51000000)
+#define TCFG1_REG		__REG(0x51000004)
+#define TCON_REG		__REG(0x51000008)
+#define TCNTB0_REG		__REG(0x5100000C)
+#define TCMPB0_REG		__REG(0x51000010)
+#define TCNTO0_REG		__REG(0x51000014)
+#define TCNTB1_REG		__REG(0x51000018)
+#define TCMPB1_REG		__REG(0x5100001C)
+#define TCNTO1_REG		__REG(0x51000020)
+#define TCNTB2_REG		__REG(0x51000024)
+#define TCMPB2_REG		__REG(0x51000028)
+#define TCNTO2_REG		__REG(0x5100002C)
+#define TCNTB3_REG		__REG(0x51000030)
+#define TCMPB3_REG		__REG(0x51000034)
+#define TCNTO3_REG		__REG(0x51000038)
+#define TCNTB4_REG		__REG(0x5100003C)
+#define TCNTO4_REG		__REG(0x51000040)
+
+/* Fields */
+#define fTCFG0_DZONE		Fld(8,16)   /* the dead zone length (= timer 0) */
+#define fTCFG0_PRE1		Fld(8,8)    /* prescaler value for time 2,3,4 */
+#define fTCFG0_PRE0		Fld(8,0)    /* prescaler value for time 0,1 */
+#define fTCFG1_MUX4		Fld(4,16)
+/* bits */
+#define TCFG0_DZONE(x)		FInsrt((x), fTCFG0_DZONE)
+#define TCFG0_PRE1(x)		FInsrt((x), fTCFG0_PRE1)
+#define TCFG0_PRE0(x)		FInsrt((x), fTCFG0_PRE0)
+#define TCON_4_AUTO		(1 << 22)   /* auto reload on/off for Timer 4 */
+#define TCON_4_UPDATE		(1 << 21)   /* manual Update TCNTB4 */
+#define TCON_4_ONOFF		(1 << 20)   /* 0: Stop, 1: start Timer 4 */
+#define COUNT_4_ON		(TCON_4_ONOFF*1)
+#define COUNT_4_OFF		(TCON_4_ONOFF*0)
+#define TCON_3_AUTO		(1 << 19)   /* auto reload on/off for Timer 3 */
+#define TIMER3_ATLOAD_ON	(TCON_3_AUTO*1)
+#define TIMER3_ATLAOD_OFF	FClrBit(TCON, TCON_3_AUTO)
+#define TCON_3_INVERT		(1 << 18)   /* 1: Inverter on for TOUT3 */
+#define TIMER3_IVT_ON		(TCON_3_INVERT*1)
+#define TIMER3_IVT_OFF		(FClrBit(TCON, TCON_3_INVERT))
+#define TCON_3_MAN		(1 << 17)   /* manual Update TCNTB3,TCMPB3 */
+#define TIMER3_MANUP		(TCON_3_MAN*1)
+#define TIMER3_NOP		(FClrBit(TCON, TCON_3_MAN))
+#define TCON_3_ONOFF		(1 << 16)   /* 0: Stop, 1: start Timer 3 */
+#define TIMER3_ON		(TCON_3_ONOFF*1)
+#define TIMER3_OFF		(FClrBit(TCON, TCON_3_ONOFF))
+/* macros */
+#define GET_PRESCALE_TIMER4(x)	FExtr((x), fTCFG0_PRE1)
+#define GET_DIVIDER_TIMER4(x)	FExtr((x), fTCFG1_MUX4)
+
+/*
+ * RTC Controller
+ */
+#define ELFIN_RTC_BASE		0x57000000
+#define RTCCON_REG		__REG(0x57000040)
+#define TICNT_REG		__REG(0x57000044)
+#define RTCALM_REG		__REG(0x57000050)
+#define ALMSEC_REG		__REG(0x57000054)
+#define ALMMIN_REG		__REG(0x57000058)
+#define ALMHOUR_REG		__REG(0x5700005c)
+#define ALMDATE_REG		__REG(0x57000060)
+#define ALMMON_REG		__REG(0x57000064)
+#define ALMYEAR_REG		__REG(0x57000068)
+#define BCDSEC_REG		__REG(0x57000070)
+#define BCDMIN_REG		__REG(0x57000074)
+#define BCDHOUR_REG		__REG(0x57000078)
+#define BCDDATE_REG		__REG(0x5700007c)
+#define BCDDAY_REG		__REG(0x57000080)
+#define BCDMON_REG		__REG(0x57000084)
+#define BCDYEAR_REG		__REG(0x57000088)
+
+/* USB Device */
+#define ELFIN_USBD_BASE		0x52000000
+#define USB_DEVICE_PHYS_ADR	ELFIN_USBD_BASE
+
+/* include common stuff */
+#ifndef __ASSEMBLY__
+static inline S3C24X0_MEMCTL *S3C24X0_GetBase_MEMCTL(void)
+{
+    return (S3C24X0_MEMCTL *) (ELFIN_MEM_CON_BASE);
+}
+static inline S3C24X0_USB_HOST *S3C24X0_GetBase_USB_HOST(void)
+{
+    return (S3C24X0_USB_HOST *) ELFIN_USB_HOST_BASE;
+}
+static inline S3C24X0_INTERRUPT *S3C24X0_GetBase_INTERRUPT(void)
+{
+    return (S3C24X0_INTERRUPT *) ELFIN_INTERRUPT_BASE;
+}
+static inline S3C24X0_DMAS *S3C24X0_GetBase_DMAS(void)
+{
+    return (S3C24X0_DMAS *) ELFIN_DMA_BASE;
+}
+static inline S3C24X0_CLOCK_POWER *S3C24X0_GetBase_CLOCK_POWER(void)
+{
+    return (S3C24X0_CLOCK_POWER *) ELFIN_CLOCK_POWER_BASE;
+}
+static inline S3C24X0_LCD *S3C24X0_GetBase_LCD(void)
+{
+    return (S3C24X0_LCD *) ELFIN_LCD_BASE;
+}
+static inline S3C2410_NAND *S3C2410_GetBase_NAND(void)
+{
+    return (S3C2410_NAND *) ELFIN_NAND_BASE;
+}
+static inline S3C24X0_UART *S3C24X0_GetBase_UART(S3C24X0_UARTS_NR nr)
+{
+    return (S3C24X0_UART *) (ELFIN_UART_BASE + (nr * 0x4000));
+}
+static inline S3C24X0_TIMERS *S3C24X0_GetBase_TIMERS(void)
+{
+    return (S3C24X0_TIMERS *) ELFIN_TIMER_BASE;
+}
+static inline S3C24X0_USB_DEVICE *S3C24X0_GetBase_USB_DEVICE(void)
+{
+    return (S3C24X0_USB_DEVICE *) ELFIN_USB_DEVICE_BASE;
+}
+static inline S3C24X0_WATCHDOG *S3C24X0_GetBase_WATCHDOG(void)
+{
+    return (S3C24X0_WATCHDOG *) ELFIN_WATCHDOG_BASE;
+}
+static inline S3C24X0_I2C *S3C24X0_GetBase_I2C(void)
+{
+    return (S3C24X0_I2C *) ELFIN_I2C_BASE;
+}
+static inline S3C24X0_I2S *S3C24X0_GetBase_I2S(void)
+{
+    return (S3C24X0_I2S *) ELFIN_I2S_BASE;
+}
+static inline S3C24X0_GPIO *S3C24X0_GetBase_GPIO(void)
+{
+    return (S3C24X0_GPIO *) ELFIN_GPIO_BASE;
+}
+static inline S3C24X0_RTC *S3C24X0_GetBase_RTC(void)
+{
+    return (S3C24X0_RTC *) ELFIN_RTC_BASE;
+}
+static inline S3C2410_ADC *S3C2410_GetBase_ADC(void)
+{
+    return (S3C2410_ADC *) ELFIN_ADC_BASE;
+}
+static inline S3C24X0_SPI *S3C24X0_GetBase_SPI(void)
+{
+    return (S3C24X0_SPI *) ELFIN_SPI_BASE;
+}
+static inline S3C2410_SDI *S3C2410_GetBase_SDI(void)
+{
+    return (S3C2410_SDI *) ELFIN_SDI_BASE;
+}
+#else                           /* #ifndef __ASSEMBLY__ */
+
+/* watchdog */
+#define WTCON_OFFSET		0x00
+
+/* LCD controller */
+#define LCDBGCON_OFFSET		0x5c
+
+#endif                          /* #ifndef __ASSEMBLY__ */
+
+/* PENDING BIT */
+#define BIT_EINT0		(0x1)
+#define BIT_EINT1		(0x1<<1)
+#define BIT_EINT2		(0x1<<2)
+#define BIT_EINT3		(0x1<<3)
+#define BIT_EINT4_7		(0x1<<4)
+#define BIT_EINT8_23		(0x1<<5)
+#define BIT_BAT_FLT		(0x1<<7)
+#define BIT_TICK		(0x1<<8)
+#define BIT_WDT			(0x1<<9)
+#define BIT_TIMER0		(0x1<<10)
+#define BIT_TIMER1		(0x1<<11)
+#define BIT_TIMER2		(0x1<<12)
+#define BIT_TIMER3		(0x1<<13)
+#define BIT_TIMER4		(0x1<<14)
+#define BIT_UART2		(0x1<<15)
+#define BIT_LCD			(0x1<<16)
+#define BIT_DMA0		(0x1<<17)
+#define BIT_DMA1		(0x1<<18)
+#define BIT_DMA2		(0x1<<19)
+#define BIT_DMA3		(0x1<<20)
+#define BIT_SDI			(0x1<<21)
+#define BIT_SPI0		(0x1<<22)
+#define BIT_UART1		(0x1<<23)
+#define BIT_USBH		(0x1<<26)
+#define BIT_IIC			(0x1<<27)
+#define BIT_UART0		(0x1<<28)
+#define BIT_SPI1		(0x1<<29)
+#define BIT_RTC			(0x1<<30)
+#define BIT_ADC			(0x1<<31)
+#define BIT_ALLMSK		(0xFFFFFFFF)
+
+#define CLKCON_USBD		(1<< 15)
+#define BIT19			0x00080000
+#define BIT29			0x20000000
+#define BIT_USBD		BIT29
+#define BIT_USBD_SUB		BIT19
+
+#define ClearPending(bit) {\
+		 rSRCPND = bit;\
+		 rINTPND = bit;\
+		 rINTPND;\
+		 }
+/* Wait until rINTPND is changed for the case that the ISR is very short. */
+
+#endif /*__S3C2440_H__*/
diff --git a/linux-bsp/asm-study/myboot/include/s3c24x0.h b/linux-bsp/asm-study/myboot/include/s3c24x0.h
new file mode 100644
index 0000000..b0e1a7d
--- /dev/null
+++ b/linux-bsp/asm-study/myboot/include/s3c24x0.h
@@ -0,0 +1,1125 @@
+/*
+ * (C) Copyright 2003
+ * David M�ller ELSOFT AG Switzerland. d.mueller@elsoft.ch
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+/************************************************
+ * NAME	    : s3c24x0.h
+ * Version  : 31.3.2003
+ *
+ * common stuff for SAMSUNG S3C24X0 SoC
+ ************************************************/
+
+#ifndef __S3C24X0_H__
+#define __S3C24X0_H__
+
+#include <asm/types.h>
+
+typedef volatile u8 S3C24X0_REG8;
+typedef volatile u16 S3C24X0_REG16;
+typedef volatile u32 S3C24X0_REG32;
+
+/* Memory controller (see manual chapter 5) */
+typedef struct
+{
+    S3C24X0_REG32 BWSCON;
+    S3C24X0_REG32 BANKCON[8];
+    S3C24X0_REG32 REFRESH;
+    S3C24X0_REG32 BANKSIZE;
+    S3C24X0_REG32 MRSRB6;
+    S3C24X0_REG32 MRSRB7;
+} /*__attribute__((__packed__))*/ S3C24X0_MEMCTL;
+
+/* USB HOST (see manual chapter 12) */
+typedef struct
+{
+    S3C24X0_REG32 HcRevision;
+    S3C24X0_REG32 HcControl;
+    S3C24X0_REG32 HcCommonStatus;
+    S3C24X0_REG32 HcInterruptStatus;
+    S3C24X0_REG32 HcInterruptEnable;
+    S3C24X0_REG32 HcInterruptDisable;
+    S3C24X0_REG32 HcHCCA;
+    S3C24X0_REG32 HcPeriodCuttendED;
+    S3C24X0_REG32 HcControlHeadED;
+    S3C24X0_REG32 HcControlCurrentED;
+    S3C24X0_REG32 HcBulkHeadED;
+    S3C24X0_REG32 HcBuldCurrentED;
+    S3C24X0_REG32 HcDoneHead;
+    S3C24X0_REG32 HcRmInterval;
+    S3C24X0_REG32 HcFmRemaining;
+    S3C24X0_REG32 HcFmNumber;
+    S3C24X0_REG32 HcPeriodicStart;
+    S3C24X0_REG32 HcLSThreshold;
+    S3C24X0_REG32 HcRhDescriptorA;
+    S3C24X0_REG32 HcRhDescriptorB;
+    S3C24X0_REG32 HcRhStatus;
+    S3C24X0_REG32 HcRhPortStatus1;
+    S3C24X0_REG32 HcRhPortStatus2;
+} /*__attribute__((__packed__))*/ S3C24X0_USB_HOST;
+
+/* INTERRUPT (see manual chapter 14) */
+typedef struct
+{
+    S3C24X0_REG32 SRCPND;
+    S3C24X0_REG32 INTMOD;
+    S3C24X0_REG32 INTMSK;
+    S3C24X0_REG32 PRIORITY;
+    S3C24X0_REG32 INTPND;
+    S3C24X0_REG32 INTOFFSET;
+#ifdef CONFIG_S3C2410
+    S3C24X0_REG32 SUBSRCPND;
+    S3C24X0_REG32 INTSUBMSK;
+#endif
+} /*__attribute__((__packed__))*/ S3C24X0_INTERRUPT;
+
+/* DMAS (see manual chapter 8) */
+typedef struct
+{
+    S3C24X0_REG32 DISRC;
+#ifdef CONFIG_S3C2410
+    S3C24X0_REG32 DISRCC;
+#endif
+    S3C24X0_REG32 DIDST;
+#ifdef CONFIG_S3C2410
+    S3C24X0_REG32 DIDSTC;
+#endif
+    S3C24X0_REG32 DCON;
+    S3C24X0_REG32 DSTAT;
+    S3C24X0_REG32 DCSRC;
+    S3C24X0_REG32 DCDST;
+    S3C24X0_REG32 DMASKTRIG;
+#ifdef CONFIG_S3C2400
+    S3C24X0_REG32 res[1];
+#endif
+#ifdef CONFIG_S3C2410
+    S3C24X0_REG32 res[7];
+#endif
+} /*__attribute__((__packed__))*/ S3C24X0_DMA;
+
+typedef struct
+{
+    S3C24X0_DMA dma[4];
+} /*__attribute__((__packed__))*/ S3C24X0_DMAS;
+
+/* CLOCK & POWER MANAGEMENT (see S3C2400 manual chapter 6) */
+/*                          (see S3C2410 manual chapter 7) */
+typedef struct
+{
+    S3C24X0_REG32 LOCKTIME;
+    S3C24X0_REG32 MPLLCON;
+    S3C24X0_REG32 UPLLCON;
+    S3C24X0_REG32 CLKCON;
+    S3C24X0_REG32 CLKSLOW;
+    S3C24X0_REG32 CLKDIVN;
+} /*__attribute__((__packed__))*/ S3C24X0_CLOCK_POWER;
+
+/* LCD CONTROLLER (see manual chapter 15) */
+typedef struct
+{
+    S3C24X0_REG32 LCDCON1;
+    S3C24X0_REG32 LCDCON2;
+    S3C24X0_REG32 LCDCON3;
+    S3C24X0_REG32 LCDCON4;
+    S3C24X0_REG32 LCDCON5;
+    S3C24X0_REG32 LCDSADDR1;
+    S3C24X0_REG32 LCDSADDR2;
+    S3C24X0_REG32 LCDSADDR3;
+    S3C24X0_REG32 REDLUT;
+    S3C24X0_REG32 GREENLUT;
+    S3C24X0_REG32 BLUELUT;
+    S3C24X0_REG32 res[8];
+    S3C24X0_REG32 DITHMODE;
+    S3C24X0_REG32 TPAL;
+#ifdef CONFIG_S3C2410
+    S3C24X0_REG32 LCDINTPND;
+    S3C24X0_REG32 LCDSRCPND;
+    S3C24X0_REG32 LCDINTMSK;
+    S3C24X0_REG32 LPCSEL;
+#endif
+} /*__attribute__((__packed__))*/ S3C24X0_LCD;
+
+/* NAND FLASH (see S3C2410 manual chapter 6) */
+typedef struct
+{
+    S3C24X0_REG32 NFCONF;
+    S3C24X0_REG32 NFCMD;
+    S3C24X0_REG32 NFADDR;
+    S3C24X0_REG32 NFDATA;
+    S3C24X0_REG32 NFSTAT;
+    S3C24X0_REG32 NFECC;
+} /*__attribute__((__packed__))*/ S3C2410_NAND;
+
+/* UART (see manual chapter 11) */
+typedef struct
+{
+    S3C24X0_REG32 ULCON;
+    S3C24X0_REG32 UCON;
+    S3C24X0_REG32 UFCON;
+    S3C24X0_REG32 UMCON;
+    S3C24X0_REG32 UTRSTAT;
+    S3C24X0_REG32 UERSTAT;
+    S3C24X0_REG32 UFSTAT;
+    S3C24X0_REG32 UMSTAT;
+#ifdef __BIG_ENDIAN
+    S3C24X0_REG8 res1[3];
+    S3C24X0_REG8 UTXH;
+    S3C24X0_REG8 res2[3];
+    S3C24X0_REG8 URXH;
+#else                           /* Little Endian */
+    S3C24X0_REG8 UTXH;
+    S3C24X0_REG8 res1[3];
+    S3C24X0_REG8 URXH;
+    S3C24X0_REG8 res2[3];
+#endif
+    S3C24X0_REG32 UBRDIV;
+} /*__attribute__((__packed__))*/ S3C24X0_UART;
+
+/* PWM TIMER (see manual chapter 10) */
+typedef struct
+{
+    S3C24X0_REG32 TCNTB;
+    S3C24X0_REG32 TCMPB;
+    S3C24X0_REG32 TCNTO;
+} /*__attribute__((__packed__))*/ S3C24X0_TIMER;
+
+typedef struct
+{
+    S3C24X0_REG32 TCFG0;
+    S3C24X0_REG32 TCFG1;
+    S3C24X0_REG32 TCON;
+    S3C24X0_TIMER ch[4];
+    S3C24X0_REG32 TCNTB4;
+    S3C24X0_REG32 TCNTO4;
+} /*__attribute__((__packed__))*/ S3C24X0_TIMERS;
+
+/* USB DEVICE (see manual chapter 13) */
+typedef struct
+{
+#ifdef __BIG_ENDIAN
+    S3C24X0_REG8 res[3];
+    S3C24X0_REG8 EP_FIFO_REG;
+#else                           /*  little endian */
+    S3C24X0_REG8 EP_FIFO_REG;
+    S3C24X0_REG8 res[3];
+#endif
+} /*__attribute__((__packed__))*/ S3C24X0_USB_DEV_FIFOS;
+
+typedef struct
+{
+#ifdef __BIG_ENDIAN
+    S3C24X0_REG8 res1[3];
+    S3C24X0_REG8 EP_DMA_CON;
+    S3C24X0_REG8 res2[3];
+    S3C24X0_REG8 EP_DMA_UNIT;
+    S3C24X0_REG8 res3[3];
+    S3C24X0_REG8 EP_DMA_FIFO;
+    S3C24X0_REG8 res4[3];
+    S3C24X0_REG8 EP_DMA_TTC_L;
+    S3C24X0_REG8 res5[3];
+    S3C24X0_REG8 EP_DMA_TTC_M;
+    S3C24X0_REG8 res6[3];
+    S3C24X0_REG8 EP_DMA_TTC_H;
+#else                           /*  little endian */
+    S3C24X0_REG8 EP_DMA_CON;
+    S3C24X0_REG8 res1[3];
+    S3C24X0_REG8 EP_DMA_UNIT;
+    S3C24X0_REG8 res2[3];
+    S3C24X0_REG8 EP_DMA_FIFO;
+    S3C24X0_REG8 res3[3];
+    S3C24X0_REG8 EP_DMA_TTC_L;
+    S3C24X0_REG8 res4[3];
+    S3C24X0_REG8 EP_DMA_TTC_M;
+    S3C24X0_REG8 res5[3];
+    S3C24X0_REG8 EP_DMA_TTC_H;
+    S3C24X0_REG8 res6[3];
+#endif
+} /*__attribute__((__packed__))*/ S3C24X0_USB_DEV_DMAS;
+
+typedef struct
+{
+#ifdef __BIG_ENDIAN
+    S3C24X0_REG8 res1[3];
+    S3C24X0_REG8 FUNC_ADDR_REG;
+    S3C24X0_REG8 res2[3];
+    S3C24X0_REG8 PWR_REG;
+    S3C24X0_REG8 res3[3];
+    S3C24X0_REG8 EP_INT_REG;
+    S3C24X0_REG8 res4[15];
+    S3C24X0_REG8 USB_INT_REG;
+    S3C24X0_REG8 res5[3];
+    S3C24X0_REG8 EP_INT_EN_REG;
+    S3C24X0_REG8 res6[15];
+    S3C24X0_REG8 USB_INT_EN_REG;
+    S3C24X0_REG8 res7[3];
+    S3C24X0_REG8 FRAME_NUM1_REG;
+    S3C24X0_REG8 res8[3];
+    S3C24X0_REG8 FRAME_NUM2_REG;
+    S3C24X0_REG8 res9[3];
+    S3C24X0_REG8 INDEX_REG;
+    S3C24X0_REG8 res10[7];
+    S3C24X0_REG8 MAXP_REG;
+    S3C24X0_REG8 res11[3];
+    S3C24X0_REG8 EP0_CSR_IN_CSR1_REG;
+    S3C24X0_REG8 res12[3];
+    S3C24X0_REG8 IN_CSR2_REG;
+    S3C24X0_REG8 res13[7];
+    S3C24X0_REG8 OUT_CSR1_REG;
+    S3C24X0_REG8 res14[3];
+    S3C24X0_REG8 OUT_CSR2_REG;
+    S3C24X0_REG8 res15[3];
+    S3C24X0_REG8 OUT_FIFO_CNT1_REG;
+    S3C24X0_REG8 res16[3];
+    S3C24X0_REG8 OUT_FIFO_CNT2_REG;
+#else                           /*  little endian */
+    S3C24X0_REG8 FUNC_ADDR_REG;
+    S3C24X0_REG8 res1[3];
+    S3C24X0_REG8 PWR_REG;
+    S3C24X0_REG8 res2[3];
+    S3C24X0_REG8 EP_INT_REG;
+    S3C24X0_REG8 res3[15];
+    S3C24X0_REG8 USB_INT_REG;
+    S3C24X0_REG8 res4[3];
+    S3C24X0_REG8 EP_INT_EN_REG;
+    S3C24X0_REG8 res5[15];
+    S3C24X0_REG8 USB_INT_EN_REG;
+    S3C24X0_REG8 res6[3];
+    S3C24X0_REG8 FRAME_NUM1_REG;
+    S3C24X0_REG8 res7[3];
+    S3C24X0_REG8 FRAME_NUM2_REG;
+    S3C24X0_REG8 res8[3];
+    S3C24X0_REG8 INDEX_REG;
+    S3C24X0_REG8 res9[7];
+    S3C24X0_REG8 MAXP_REG;
+    S3C24X0_REG8 res10[7];
+    S3C24X0_REG8 EP0_CSR_IN_CSR1_REG;
+    S3C24X0_REG8 res11[3];
+    S3C24X0_REG8 IN_CSR2_REG;
+    S3C24X0_REG8 res12[3];
+    S3C24X0_REG8 OUT_CSR1_REG;
+    S3C24X0_REG8 res13[7];
+    S3C24X0_REG8 OUT_CSR2_REG;
+    S3C24X0_REG8 res14[3];
+    S3C24X0_REG8 OUT_FIFO_CNT1_REG;
+    S3C24X0_REG8 res15[3];
+    S3C24X0_REG8 OUT_FIFO_CNT2_REG;
+    S3C24X0_REG8 res16[3];
+#endif                          /*  __BIG_ENDIAN */
+    S3C24X0_USB_DEV_FIFOS fifo[5];
+    S3C24X0_USB_DEV_DMAS dma[5];
+} /*__attribute__((__packed__))*/ S3C24X0_USB_DEVICE;
+
+/* WATCH DOG TIMER (see manual chapter 18) */
+typedef struct
+{
+    S3C24X0_REG32 WTCON;
+    S3C24X0_REG32 WTDAT;
+    S3C24X0_REG32 WTCNT;
+} /*__attribute__((__packed__))*/ S3C24X0_WATCHDOG;
+
+/* IIC (see manual chapter 20) */
+typedef struct
+{
+    S3C24X0_REG32 IICCON;
+    S3C24X0_REG32 IICSTAT;
+    S3C24X0_REG32 IICADD;
+    S3C24X0_REG32 IICDS;
+} /*__attribute__((__packed__))*/ S3C24X0_I2C;
+
+/* IIS (see manual chapter 21) */
+typedef struct
+{
+#ifdef __BIG_ENDIAN
+    S3C24X0_REG16 res1;
+    S3C24X0_REG16 IISCON;
+    S3C24X0_REG16 res2;
+    S3C24X0_REG16 IISMOD;
+    S3C24X0_REG16 res3;
+    S3C24X0_REG16 IISPSR;
+    S3C24X0_REG16 res4;
+    S3C24X0_REG16 IISFCON;
+    S3C24X0_REG16 res5;
+    S3C24X0_REG16 IISFIFO;
+#else                           /*  little endian */
+    S3C24X0_REG16 IISCON;
+    S3C24X0_REG16 res1;
+    S3C24X0_REG16 IISMOD;
+    S3C24X0_REG16 res2;
+    S3C24X0_REG16 IISPSR;
+    S3C24X0_REG16 res3;
+    S3C24X0_REG16 IISFCON;
+    S3C24X0_REG16 res4;
+    S3C24X0_REG16 IISFIFO;
+    S3C24X0_REG16 res5;
+#endif
+} /*__attribute__((__packed__))*/ S3C24X0_I2S;
+
+/* I/O PORT (see manual chapter 9) */
+typedef struct
+{
+#ifdef CONFIG_S3C2400
+    S3C24X0_REG32 PACON;
+    S3C24X0_REG32 PADAT;
+
+    S3C24X0_REG32 PBCON;
+    S3C24X0_REG32 PBDAT;
+    S3C24X0_REG32 PBUP;
+
+    S3C24X0_REG32 PCCON;
+    S3C24X0_REG32 PCDAT;
+    S3C24X0_REG32 PCUP;
+
+    S3C24X0_REG32 PDCON;
+    S3C24X0_REG32 PDDAT;
+    S3C24X0_REG32 PDUP;
+
+    S3C24X0_REG32 PECON;
+    S3C24X0_REG32 PEDAT;
+    S3C24X0_REG32 PEUP;
+
+    S3C24X0_REG32 PFCON;
+    S3C24X0_REG32 PFDAT;
+    S3C24X0_REG32 PFUP;
+
+    S3C24X0_REG32 PGCON;
+    S3C24X0_REG32 PGDAT;
+    S3C24X0_REG32 PGUP;
+
+    S3C24X0_REG32 OPENCR;
+
+    S3C24X0_REG32 MISCCR;
+    S3C24X0_REG32 EXTINT;
+#endif
+#ifdef CONFIG_S3C2410
+    S3C24X0_REG32 GPACON;
+    S3C24X0_REG32 GPADAT;
+    S3C24X0_REG32 res1[2];
+    S3C24X0_REG32 GPBCON;
+    S3C24X0_REG32 GPBDAT;
+    S3C24X0_REG32 GPBUP;
+    S3C24X0_REG32 res2;
+    S3C24X0_REG32 GPCCON;
+    S3C24X0_REG32 GPCDAT;
+    S3C24X0_REG32 GPCUP;
+    S3C24X0_REG32 res3;
+    S3C24X0_REG32 GPDCON;
+    S3C24X0_REG32 GPDDAT;
+    S3C24X0_REG32 GPDUP;
+    S3C24X0_REG32 res4;
+    S3C24X0_REG32 GPECON;
+    S3C24X0_REG32 GPEDAT;
+    S3C24X0_REG32 GPEUP;
+    S3C24X0_REG32 res5;
+    S3C24X0_REG32 GPFCON;
+    S3C24X0_REG32 GPFDAT;
+    S3C24X0_REG32 GPFUP;
+    S3C24X0_REG32 res6;
+    S3C24X0_REG32 GPGCON;
+    S3C24X0_REG32 GPGDAT;
+    S3C24X0_REG32 GPGUP;
+    S3C24X0_REG32 res7;
+    S3C24X0_REG32 GPHCON;
+    S3C24X0_REG32 GPHDAT;
+    S3C24X0_REG32 GPHUP;
+    S3C24X0_REG32 res8;
+
+    S3C24X0_REG32 MISCCR;
+    S3C24X0_REG32 DCLKCON;
+    S3C24X0_REG32 EXTINT0;
+    S3C24X0_REG32 EXTINT1;
+    S3C24X0_REG32 EXTINT2;
+    S3C24X0_REG32 EINTFLT0;
+    S3C24X0_REG32 EINTFLT1;
+    S3C24X0_REG32 EINTFLT2;
+    S3C24X0_REG32 EINTFLT3;
+    S3C24X0_REG32 EINTMASK;
+    S3C24X0_REG32 EINTPEND;
+    S3C24X0_REG32 GSTATUS0;
+    S3C24X0_REG32 GSTATUS1;
+    S3C24X0_REG32 GSTATUS2;
+    S3C24X0_REG32 GSTATUS3;
+    S3C24X0_REG32 GSTATUS4;
+#endif
+} /*__attribute__((__packed__))*/ S3C24X0_GPIO;
+
+/* RTC (see manual chapter 17) */
+typedef struct
+{
+#ifdef __BIG_ENDIAN
+    S3C24X0_REG8 res1[67];
+    S3C24X0_REG8 RTCCON;
+    S3C24X0_REG8 res2[3];
+    S3C24X0_REG8 TICNT;
+    S3C24X0_REG8 res3[11];
+    S3C24X0_REG8 RTCALM;
+    S3C24X0_REG8 res4[3];
+    S3C24X0_REG8 ALMSEC;
+    S3C24X0_REG8 res5[3];
+    S3C24X0_REG8 ALMMIN;
+    S3C24X0_REG8 res6[3];
+    S3C24X0_REG8 ALMHOUR;
+    S3C24X0_REG8 res7[3];
+    S3C24X0_REG8 ALMDATE;
+    S3C24X0_REG8 res8[3];
+    S3C24X0_REG8 ALMMON;
+    S3C24X0_REG8 res9[3];
+    S3C24X0_REG8 ALMYEAR;
+    S3C24X0_REG8 res10[3];
+    S3C24X0_REG8 RTCRST;
+    S3C24X0_REG8 res11[3];
+    S3C24X0_REG8 BCDSEC;
+    S3C24X0_REG8 res12[3];
+    S3C24X0_REG8 BCDMIN;
+    S3C24X0_REG8 res13[3];
+    S3C24X0_REG8 BCDHOUR;
+    S3C24X0_REG8 res14[3];
+    S3C24X0_REG8 BCDDATE;
+    S3C24X0_REG8 res15[3];
+    S3C24X0_REG8 BCDDAY;
+    S3C24X0_REG8 res16[3];
+    S3C24X0_REG8 BCDMON;
+    S3C24X0_REG8 res17[3];
+    S3C24X0_REG8 BCDYEAR;
+#else                           /*  little endian */
+    S3C24X0_REG8 res0[64];
+    S3C24X0_REG8 RTCCON;
+    S3C24X0_REG8 res1[3];
+    S3C24X0_REG8 TICNT;
+    S3C24X0_REG8 res2[11];
+    S3C24X0_REG8 RTCALM;
+    S3C24X0_REG8 res3[3];
+    S3C24X0_REG8 ALMSEC;
+    S3C24X0_REG8 res4[3];
+    S3C24X0_REG8 ALMMIN;
+    S3C24X0_REG8 res5[3];
+    S3C24X0_REG8 ALMHOUR;
+    S3C24X0_REG8 res6[3];
+    S3C24X0_REG8 ALMDATE;
+    S3C24X0_REG8 res7[3];
+    S3C24X0_REG8 ALMMON;
+    S3C24X0_REG8 res8[3];
+    S3C24X0_REG8 ALMYEAR;
+    S3C24X0_REG8 res9[3];
+    S3C24X0_REG8 RTCRST;
+    S3C24X0_REG8 res10[3];
+    S3C24X0_REG8 BCDSEC;
+    S3C24X0_REG8 res11[3];
+    S3C24X0_REG8 BCDMIN;
+    S3C24X0_REG8 res12[3];
+    S3C24X0_REG8 BCDHOUR;
+    S3C24X0_REG8 res13[3];
+    S3C24X0_REG8 BCDDATE;
+    S3C24X0_REG8 res14[3];
+    S3C24X0_REG8 BCDDAY;
+    S3C24X0_REG8 res15[3];
+    S3C24X0_REG8 BCDMON;
+    S3C24X0_REG8 res16[3];
+    S3C24X0_REG8 BCDYEAR;
+    S3C24X0_REG8 res17[3];
+#endif
+} /*__attribute__((__packed__))*/ S3C24X0_RTC;
+
+/* ADC (see manual chapter 16) */
+typedef struct
+{
+    S3C24X0_REG32 ADCCON;
+    S3C24X0_REG32 ADCDAT;
+} /*__attribute__((__packed__))*/ S3C2400_ADC;
+
+/* ADC (see manual chapter 16) */
+typedef struct
+{
+    S3C24X0_REG32 ADCCON;
+    S3C24X0_REG32 ADCTSC;
+    S3C24X0_REG32 ADCDLY;
+    S3C24X0_REG32 ADCDAT0;
+    S3C24X0_REG32 ADCDAT1;
+} /*__attribute__((__packed__))*/ S3C2410_ADC;
+
+/* SPI (see manual chapter 22) */
+typedef struct
+{
+    S3C24X0_REG32 SPCON;
+    S3C24X0_REG32 SPSTA;
+    S3C24X0_REG32 SPPIN;
+    S3C24X0_REG32 SPPRE;
+    S3C24X0_REG32 SPTDAT;
+    S3C24X0_REG32 SPRDAT;
+    S3C24X0_REG32 res[2];
+} __attribute__ ((__packed__)) S3C24X0_SPI_CHANNEL;
+
+typedef struct
+{
+    S3C24X0_SPI_CHANNEL ch[S3C24X0_SPI_CHANNELS];
+} /*__attribute__((__packed__))*/ S3C24X0_SPI;
+
+/* MMC INTERFACE (see S3C2400 manual chapter 19) */
+typedef struct
+{
+#ifdef __BIG_ENDIAN
+    S3C24X0_REG8 res1[3];
+    S3C24X0_REG8 MMCON;
+    S3C24X0_REG8 res2[3];
+    S3C24X0_REG8 MMCRR;
+    S3C24X0_REG8 res3[3];
+    S3C24X0_REG8 MMFCON;
+    S3C24X0_REG8 res4[3];
+    S3C24X0_REG8 MMSTA;
+    S3C24X0_REG16 res5;
+    S3C24X0_REG16 MMFSTA;
+    S3C24X0_REG8 res6[3];
+    S3C24X0_REG8 MMPRE;
+    S3C24X0_REG16 res7;
+    S3C24X0_REG16 MMLEN;
+    S3C24X0_REG8 res8[3];
+    S3C24X0_REG8 MMCR7;
+    S3C24X0_REG32 MMRSP[4];
+    S3C24X0_REG8 res9[3];
+    S3C24X0_REG8 MMCMD0;
+    S3C24X0_REG32 MMCMD1;
+    S3C24X0_REG16 res10;
+    S3C24X0_REG16 MMCR16;
+    S3C24X0_REG8 res11[3];
+    S3C24X0_REG8 MMDAT;
+#else
+    S3C24X0_REG8 MMCON;
+    S3C24X0_REG8 res1[3];
+    S3C24X0_REG8 MMCRR;
+    S3C24X0_REG8 res2[3];
+    S3C24X0_REG8 MMFCON;
+    S3C24X0_REG8 res3[3];
+    S3C24X0_REG8 MMSTA;
+    S3C24X0_REG8 res4[3];
+    S3C24X0_REG16 MMFSTA;
+    S3C24X0_REG16 res5;
+    S3C24X0_REG8 MMPRE;
+    S3C24X0_REG8 res6[3];
+    S3C24X0_REG16 MMLEN;
+    S3C24X0_REG16 res7;
+    S3C24X0_REG8 MMCR7;
+    S3C24X0_REG8 res8[3];
+    S3C24X0_REG32 MMRSP[4];
+    S3C24X0_REG8 MMCMD0;
+    S3C24X0_REG8 res9[3];
+    S3C24X0_REG32 MMCMD1;
+    S3C24X0_REG16 MMCR16;
+    S3C24X0_REG16 res10;
+    S3C24X0_REG8 MMDAT;
+    S3C24X0_REG8 res11[3];
+#endif
+} /*__attribute__((__packed__))*/ S3C2400_MMC;
+
+/* SD INTERFACE (see S3C2410 manual chapter 19) */
+typedef struct
+{
+    S3C24X0_REG32 SDICON;
+    S3C24X0_REG32 SDIPRE;
+    S3C24X0_REG32 SDICARG;
+    S3C24X0_REG32 SDICCON;
+    S3C24X0_REG32 SDICSTA;
+    S3C24X0_REG32 SDIRSP0;
+    S3C24X0_REG32 SDIRSP1;
+    S3C24X0_REG32 SDIRSP2;
+    S3C24X0_REG32 SDIRSP3;
+    S3C24X0_REG32 SDIDTIMER;
+    S3C24X0_REG32 SDIBSIZE;
+    S3C24X0_REG32 SDIDCON;
+    S3C24X0_REG32 SDIDCNT;
+    S3C24X0_REG32 SDIDSTA;
+    S3C24X0_REG32 SDIFSTA;
+#ifdef __BIG_ENDIAN
+    S3C24X0_REG8 res[3];
+    S3C24X0_REG8 SDIDAT;
+#else
+    S3C24X0_REG8 SDIDAT;
+    S3C24X0_REG8 res[3];
+#endif
+    S3C24X0_REG32 SDIIMSK;
+} /*__attribute__((__packed__))*/ S3C2410_SDI;
+
+#if 0
+/* Memory control */
+#define rBWSCON			(*(volatile unsigned *)0x48000000)
+#define rBANKCON0		(*(volatile unsigned *)0x48000004)
+#define rBANKCON1		(*(volatile unsigned *)0x48000008)
+#define rBANKCON2		(*(volatile unsigned *)0x4800000C)
+#define rBANKCON3		(*(volatile unsigned *)0x48000010)
+#define rBANKCON4		(*(volatile unsigned *)0x48000014)
+#define rBANKCON5		(*(volatile unsigned *)0x48000018)
+#define rBANKCON6		(*(volatile unsigned *)0x4800001C)
+#define rBANKCON7		(*(volatile unsigned *)0x48000020)
+#define rREFRESH		(*(volatile unsigned *)0x48000024)
+#define rBANKSIZE		(*(volatile unsigned *)0x48000028)
+#define rMRSRB6			(*(volatile unsigned *)0x4800002C)
+#define rMRSRB7			(*(volatile unsigned *)0x48000030)
+
+/* USB HOST */
+#define rHcRevision		(*(volatile unsigned *)0x49000000)
+#define rHcControl		(*(volatile unsigned *)0x49000004)
+#define rHcCommonStatus		(*(volatile unsigned *)0x49000008)
+#define rHcInterruptStatus	(*(volatile unsigned *)0x4900000C)
+#define rHcInterruptEnable	(*(volatile unsigned *)0x49000010)
+#define rHcInterruptDisable	(*(volatile unsigned *)0x49000014)
+#define rHcHCCA			(*(volatile unsigned *)0x49000018)
+#define rHcPeriodCuttendED	(*(volatile unsigned *)0x4900001C)
+#define rHcControlHeadED	(*(volatile unsigned *)0x49000020)
+#define rHcControlCurrentED	(*(volatile unsigned *)0x49000024)
+#define rHcBulkHeadED		(*(volatile unsigned *)0x49000028)
+#define rHcBuldCurrentED	(*(volatile unsigned *)0x4900002C)
+#define rHcDoneHead		(*(volatile unsigned *)0x49000030)
+#define rHcRmInterval		(*(volatile unsigned *)0x49000034)
+#define rHcFmRemaining		(*(volatile unsigned *)0x49000038)
+#define rHcFmNumber		(*(volatile unsigned *)0x4900003C)
+#define rHcPeriodicStart	(*(volatile unsigned *)0x49000040)
+#define rHcLSThreshold		(*(volatile unsigned *)0x49000044)
+#define rHcRhDescriptorA	(*(volatile unsigned *)0x49000048)
+#define rHcRhDescriptorB	(*(volatile unsigned *)0x4900004C)
+#define rHcRhStatus		(*(volatile unsigned *)0x49000050)
+#define rHcRhPortStatus1	(*(volatile unsigned *)0x49000054)
+#define rHcRhPortStatus2	(*(volatile unsigned *)0x49000058)
+
+/* INTERRUPT */
+#define rSRCPND			(*(volatile unsigned *)0x4A000000)
+#define rINTMOD			(*(volatile unsigned *)0x4A000004)
+#define rINTMSK			(*(volatile unsigned *)0x4A000008)
+#define rPRIORITY		(*(volatile unsigned *)0x4A00000C)
+#define rINTPND			(*(volatile unsigned *)0x4A000010)
+#define rINTOFFSET		(*(volatile unsigned *)0x4A000014)
+#define rSUBSRCPND		(*(volatile unsigned *)0x4A000018)
+#define rINTSUBMSK		(*(volatile unsigned *)0x4A00001C)
+
+/* DMA */
+#define rDISRC0			(*(volatile unsigned *)0x4B000000)
+#define rDISRCC0		(*(volatile unsigned *)0x4B000004)
+#define rDIDST0			(*(volatile unsigned *)0x4B000008)
+#define rDIDSTC0		(*(volatile unsigned *)0x4B00000C)
+#define rDCON0			(*(volatile unsigned *)0x4B000010)
+#define rDSTAT0			(*(volatile unsigned *)0x4B000014)
+#define rDCSRC0			(*(volatile unsigned *)0x4B000018)
+#define rDCDST0			(*(volatile unsigned *)0x4B00001C)
+#define rDMASKTRIG0		(*(volatile unsigned *)0x4B000020)
+#define rDISRC1			(*(volatile unsigned *)0x4B000040)
+#define rDISRCC1		(*(volatile unsigned *)0x4B000044)
+#define rDIDST1			(*(volatile unsigned *)0x4B000048)
+#define rDIDSTC1		(*(volatile unsigned *)0x4B00004C)
+#define rDCON1			(*(volatile unsigned *)0x4B000050)
+#define rDSTAT1			(*(volatile unsigned *)0x4B000054)
+#define rDCSRC1			(*(volatile unsigned *)0x4B000058)
+#define rDCDST1			(*(volatile unsigned *)0x4B00005C)
+#define rDMASKTRIG1		(*(volatile unsigned *)0x4B000060)
+#define rDISRC2			(*(volatile unsigned *)0x4B000080)
+#define rDISRCC2		(*(volatile unsigned *)0x4B000084)
+#define rDIDST2			(*(volatile unsigned *)0x4B000088)
+#define rDIDSTC2		(*(volatile unsigned *)0x4B00008C)
+#define rDCON2			(*(volatile unsigned *)0x4B000090)
+#define rDSTAT2			(*(volatile unsigned *)0x4B000094)
+#define rDCSRC2			(*(volatile unsigned *)0x4B000098)
+#define rDCDST2			(*(volatile unsigned *)0x4B00009C)
+#define rDMASKTRIG2		(*(volatile unsigned *)0x4B0000A0)
+#define rDISRC3			(*(volatile unsigned *)0x4B0000C0)
+#define rDISRCC3		(*(volatile unsigned *)0x4B0000C4)
+#define rDIDST3			(*(volatile unsigned *)0x4B0000C8)
+#define rDIDSTC3		(*(volatile unsigned *)0x4B0000CC)
+#define rDCON3			(*(volatile unsigned *)0x4B0000D0)
+#define rDSTAT3			(*(volatile unsigned *)0x4B0000D4)
+#define rDCSRC3			(*(volatile unsigned *)0x4B0000D8)
+#define rDCDST3			(*(volatile unsigned *)0x4B0000DC)
+#define rDMASKTRIG3		(*(volatile unsigned *)0x4B0000E0)
+
+/* CLOCK & POWER MANAGEMENT */
+#define rLOCKTIME		(*(volatile unsigned *)0x4C000000)
+#define rMPLLCON		(*(volatile unsigned *)0x4C000004)
+#define rUPLLCON		(*(volatile unsigned *)0x4C000008)
+#define rCLKCON			(*(volatile unsigned *)0x4C00000C)
+#define rCLKSLOW		(*(volatile unsigned *)0x4C000010)
+#define rCLKDIVN		(*(volatile unsigned *)0x4C000014)
+
+/* LCD CONTROLLER */
+#define rLCDCON1		(*(volatile unsigned *)0x4D000000)
+#define rLCDCON2		(*(volatile unsigned *)0x4D000004)
+#define rLCDCON3		(*(volatile unsigned *)0x4D000008)
+#define rLCDCON4		(*(volatile unsigned *)0x4D00000C)
+#define rLCDCON5		(*(volatile unsigned *)0x4D000010)
+#define rLCDSADDR1		(*(volatile unsigned *)0x4D000014)
+#define rLCDSADDR2		(*(volatile unsigned *)0x4D000018)
+#define rLCDSADDR3		(*(volatile unsigned *)0x4D00001C)
+#define rREDLUT			(*(volatile unsigned *)0x4D000020)
+#define rGREENLUT		(*(volatile unsigned *)0x4D000024)
+#define rBLUELUT		(*(volatile unsigned *)0x4D000028)
+#define rDITHMODE		(*(volatile unsigned *)0x4D00004C)
+#define rTPAL			(*(volatile unsigned *)0x4D000050)
+#define rLCDINTPND		(*(volatile unsigned *)0x4D000054)
+#define rLCDSRCPND		(*(volatile unsigned *)0x4D000058)
+#define rLCDINTMSK		(*(volatile unsigned *)0x4D00005C)
+
+/* NAND FLASH */
+#define rNFCONF			(*(volatile unsigned *)0x4E000000)
+#define rNFCMD			(*(volatile unsigned *)0x4E000004)
+#define rNFADDR			(*(volatile unsigned *)0x4E000008)
+#define rNFDATA			(*(volatile unsigned *)0x4E00000C)
+#define rNFSTAT			(*(volatile unsigned *)0x4E000010)
+#define rNFECC			(*(volatile unsigned *)0x4E000014)
+
+/* UART */
+#define rULCON0			(*(volatile unsigned *)0x50000000)
+#define rUCON0			(*(volatile unsigned *)0x50000004)
+#define rUFCON0			(*(volatile unsigned *)0x50000008)
+#define rUMCON0			(*(volatile unsigned *)0x5000000C)
+#define rUTRSTAT0		(*(volatile unsigned *)0x50000010)
+#define rUERSTAT0		(*(volatile unsigned *)0x50000014)
+#define rUFSTAT0		(*(volatile unsigned *)0x50000018)
+#define rUMSTAT0		(*(volatile unsigned *)0x5000001C)
+#define rUBRDIV0		(*(volatile unsigned *)0x50000028)
+
+#define rULCON1			(*(volatile unsigned *)0x50004000)
+#define rUCON1			(*(volatile unsigned *)0x50004004)
+#define rUFCON1			(*(volatile unsigned *)0x50004008)
+#define rUMCON1			(*(volatile unsigned *)0x5000400C)
+#define rUTRSTAT1		(*(volatile unsigned *)0x50004010)
+#define rUERSTAT1		(*(volatile unsigned *)0x50004014)
+#define rUFSTAT1		(*(volatile unsigned *)0x50004018)
+#define rUMSTAT1		(*(volatile unsigned *)0x5000401C)
+#define rUBRDIV1		(*(volatile unsigned *)0x50004028)
+
+#define rULCON2			(*(volatile unsigned *)0x50008000)
+#define rUCON2			(*(volatile unsigned *)0x50008004)
+#define rUFCON2			(*(volatile unsigned *)0x50008008)
+#define rUTRSTAT2		(*(volatile unsigned *)0x50008010)
+#define rUERSTAT2		(*(volatile unsigned *)0x50008014)
+#define rUFSTAT2		(*(volatile unsigned *)0x50008018)
+#define rUBRDIV2		(*(volatile unsigned *)0x50008028)
+
+#ifdef __BIG_ENDIAN
+#define rUTXH0			(*(volatile unsigned char *)0x50000023)
+#define rURXH0			(*(volatile unsigned char *)0x50000027)
+#define rUTXH1			(*(volatile unsigned char *)0x50004023)
+#define rURXH1			(*(volatile unsigned char *)0x50004027)
+#define rUTXH2			(*(volatile unsigned char *)0x50008023)
+#define rURXH2			(*(volatile unsigned char *)0x50008027)
+
+#define WrUTXH0(ch)		(*(volatile unsigned char *)0x50000023)=(unsigned char)(ch)
+#define RdURXH0()		(*(volatile unsigned char *)0x50000027)
+#define WrUTXH1(ch)		(*(volatile unsigned char *)0x50004023)=(unsigned char)(ch)
+#define RdURXH1()		(*(volatile unsigned char *)0x50004027)
+#define WrUTXH2(ch)		(*(volatile unsigned char *)0x50008023)=(unsigned char)(ch)
+#define RdURXH2()		(*(volatile unsigned char *)0x50008027)
+
+#define UTXH0			(0x50000020+3)  /* byte_access address by DMA */
+#define URXH0			(0x50000024+3)
+#define UTXH1			(0x50004020+3)
+#define URXH1			(0x50004024+3)
+#define UTXH2			(0x50008020+3)
+#define URXH2			(0x50008024+3)
+
+#else                           /* Little Endian */
+#define rUTXH0			(*(volatile unsigned char *)0x50000020)
+#define rURXH0			(*(volatile unsigned char *)0x50000024)
+#define rUTXH1			(*(volatile unsigned char *)0x50004020)
+#define rURXH1			(*(volatile unsigned char *)0x50004024)
+#define rUTXH2			(*(volatile unsigned char *)0x50008020)
+#define rURXH2			(*(volatile unsigned char *)0x50008024)
+
+#define WrUTXH0(ch)		(*(volatile unsigned char *)0x50000020)=(unsigned char)(ch)
+#define RdURXH0()		(*(volatile unsigned char *)0x50000024)
+#define WrUTXH1(ch)		(*(volatile unsigned char *)0x50004020)=(unsigned char)(ch)
+#define RdURXH1()		(*(volatile unsigned char *)0x50004024)
+#define WrUTXH2(ch)		(*(volatile unsigned char *)0x50008020)=(unsigned char)(ch)
+#define RdURXH2()		(*(volatile unsigned char *)0x50008024)
+
+#define UTXH0			(0x50000020)    /* byte_access address by DMA */
+#define URXH0			(0x50000024)
+#define UTXH1			(0x50004020)
+#define URXH1			(0x50004024)
+#define UTXH2			(0x50008020)
+#define URXH2			(0x50008024)
+#endif
+
+/* PWM TIMER */
+#define rTCFG0			(*(volatile unsigned *)0x51000000)
+#define rTCFG1			(*(volatile unsigned *)0x51000004)
+#define rTCON			(*(volatile unsigned *)0x51000008)
+#define rTCNTB0			(*(volatile unsigned *)0x5100000C)
+#define rTCMPB0			(*(volatile unsigned *)0x51000010)
+#define rTCNTO0			(*(volatile unsigned *)0x51000014)
+#define rTCNTB1			(*(volatile unsigned *)0x51000018)
+#define rTCMPB1			(*(volatile unsigned *)0x5100001C)
+#define rTCNTO1			(*(volatile unsigned *)0x51000020)
+#define rTCNTB2			(*(volatile unsigned *)0x51000024)
+#define rTCMPB2			(*(volatile unsigned *)0x51000028)
+#define rTCNTO2			(*(volatile unsigned *)0x5100002C)
+#define rTCNTB3			(*(volatile unsigned *)0x51000030)
+#define rTCMPB3			(*(volatile unsigned *)0x51000034)
+#define rTCNTO3			(*(volatile unsigned *)0x51000038)
+#define rTCNTB4			(*(volatile unsigned *)0x5100003C)
+#define rTCNTO4			(*(volatile unsigned *)0x51000040)
+
+/* USB DEVICE */
+#ifdef __BIG_ENDIAN
+#define rFUNC_ADDR_REG		(*(volatile unsigned char *)0x52000143)
+#define rPWR_REG		(*(volatile unsigned char *)0x52000147)
+#define rEP_INT_REG		(*(volatile unsigned char *)0x5200014B)
+#define rUSB_INT_REG		(*(volatile unsigned char *)0x5200015B)
+#define rEP_INT_EN_REG		(*(volatile unsigned char *)0x5200015F)
+#define rUSB_INT_EN_REG		(*(volatile unsigned char *)0x5200016F)
+#define rFRAME_NUM1_REG		(*(volatile unsigned char *)0x52000173)
+#define rFRAME_NUM2_REG		(*(volatile unsigned char *)0x52000177)
+#define rINDEX_REG		(*(volatile unsigned char *)0x5200017B)
+#define rMAXP_REG		(*(volatile unsigned char *)0x52000183)
+#define rEP0_CSR		(*(volatile unsigned char *)0x52000187)
+#define rIN_CSR1_REG		(*(volatile unsigned char *)0x52000187)
+#define rIN_CSR2_REG		(*(volatile unsigned char *)0x5200018B)
+#define rOUT_CSR1_REG		(*(volatile unsigned char *)0x52000193)
+#define rOUT_CSR2_REG		(*(volatile unsigned char *)0x52000197)
+#define rOUT_FIFO_CNT1_REG	(*(volatile unsigned char *)0x5200019B)
+#define rOUT_FIFO_CNT2_REG	(*(volatile unsigned char *)0x5200019F)
+#define rEP0_FIFO		(*(volatile unsigned char *)0x520001C3)
+#define rEP1_FIFO		(*(volatile unsigned char *)0x520001C7)
+#define rEP2_FIFO		(*(volatile unsigned char *)0x520001CB)
+#define rEP3_FIFO		(*(volatile unsigned char *)0x520001CF)
+#define rEP4_FIFO		(*(volatile unsigned char *)0x520001D3)
+#define rEP1_DMA_CON		(*(volatile unsigned char *)0x52000203)
+#define rEP1_DMA_UNIT		(*(volatile unsigned char *)0x52000207)
+#define rEP1_DMA_FIFO		(*(volatile unsigned char *)0x5200020B)
+#define rEP1_DMA_TX_LO		(*(volatile unsigned char *)0x5200020F)
+#define rEP1_DMA_TX_MD		(*(volatile unsigned char *)0x52000213)
+#define rEP1_DMA_TX_HI		(*(volatile unsigned char *)0x52000217)
+#define rEP2_DMA_CON		(*(volatile unsigned char *)0x5200021B)
+#define rEP2_DMA_UNIT		(*(volatile unsigned char *)0x5200021F)
+#define rEP2_DMA_FIFO		(*(volatile unsigned char *)0x52000223)
+#define rEP2_DMA_TX_LO		(*(volatile unsigned char *)0x52000227)
+#define rEP2_DMA_TX_MD		(*(volatile unsigned char *)0x5200022B)
+#define rEP2_DMA_TX_HI		(*(volatile unsigned char *)0x5200022F)
+#define rEP3_DMA_CON		(*(volatile unsigned char *)0x52000243)
+#define rEP3_DMA_UNIT		(*(volatile unsigned char *)0x52000247)
+#define rEP3_DMA_FIFO		(*(volatile unsigned char *)0x5200024B)
+#define rEP3_DMA_TX_LO		(*(volatile unsigned char *)0x5200024F)
+#define rEP3_DMA_TX_MD		(*(volatile unsigned char *)0x52000253)
+#define rEP3_DMA_TX_HI		(*(volatile unsigned char *)0x52000257)
+#define rEP4_DMA_CON		(*(volatile unsigned char *)0x5200025B)
+#define rEP4_DMA_UNIT		(*(volatile unsigned char *)0x5200025F)
+#define rEP4_DMA_FIFO		(*(volatile unsigned char *)0x52000263)
+#define rEP4_DMA_TX_LO		(*(volatile unsigned char *)0x52000267)
+#define rEP4_DMA_TX_MD		(*(volatile unsigned char *)0x5200026B)
+#define rEP4_DMA_TX_HI		(*(volatile unsigned char *)0x5200026F)
+#else                           /*  little endian */
+#define rFUNC_ADDR_REG		(*(volatile unsigned char *)0x52000140)
+#define rPWR_REG		(*(volatile unsigned char *)0x52000144)
+#define rEP_INT_REG		(*(volatile unsigned char *)0x52000148)
+#define rUSB_INT_REG		(*(volatile unsigned char *)0x52000158)
+#define rEP_INT_EN_REG		(*(volatile unsigned char *)0x5200015C)
+#define rUSB_INT_EN_REG		(*(volatile unsigned char *)0x5200016C)
+#define rFRAME_NUM1_REG		(*(volatile unsigned char *)0x52000170)
+#define rFRAME_NUM2_REG		(*(volatile unsigned char *)0x52000174)
+#define rINDEX_REG		(*(volatile unsigned char *)0x52000178)
+#define rMAXP_REG		(*(volatile unsigned char *)0x52000180)
+#define rEP0_CSR		(*(volatile unsigned char *)0x52000184)
+#define rIN_CSR1_REG		(*(volatile unsigned char *)0x52000184)
+#define rIN_CSR2_REG		(*(volatile unsigned char *)0x52000188)
+#define rOUT_CSR1_REG		(*(volatile unsigned char *)0x52000190)
+#define rOUT_CSR2_REG		(*(volatile unsigned char *)0x52000194)
+#define rOUT_FIFO_CNT1_REG	(*(volatile unsigned char *)0x52000198)
+#define rOUT_FIFO_CNT2_REG	(*(volatile unsigned char *)0x5200019C)
+#define rEP0_FIFO		(*(volatile unsigned char *)0x520001C0)
+#define rEP1_FIFO		(*(volatile unsigned char *)0x520001C4)
+#define rEP2_FIFO		(*(volatile unsigned char *)0x520001C8)
+#define rEP3_FIFO		(*(volatile unsigned char *)0x520001CC)
+#define rEP4_FIFO		(*(volatile unsigned char *)0x520001D0)
+#define rEP1_DMA_CON		(*(volatile unsigned char *)0x52000200)
+#define rEP1_DMA_UNIT		(*(volatile unsigned char *)0x52000204)
+#define rEP1_DMA_FIFO		(*(volatile unsigned char *)0x52000208)
+#define rEP1_DMA_TX_LO		(*(volatile unsigned char *)0x5200020C)
+#define rEP1_DMA_TX_MD		(*(volatile unsigned char *)0x52000210)
+#define rEP1_DMA_TX_HI		(*(volatile unsigned char *)0x52000214)
+#define rEP2_DMA_CON		(*(volatile unsigned char *)0x52000218)
+#define rEP2_DMA_UNIT		(*(volatile unsigned char *)0x5200021C)
+#define rEP2_DMA_FIFO		(*(volatile unsigned char *)0x52000220)
+#define rEP2_DMA_TX_LO		(*(volatile unsigned char *)0x52000224)
+#define rEP2_DMA_TX_MD		(*(volatile unsigned char *)0x52000228)
+#define rEP2_DMA_TX_HI		(*(volatile unsigned char *)0x5200022C)
+#define rEP3_DMA_CON		(*(volatile unsigned char *)0x52000240)
+#define rEP3_DMA_UNIT		(*(volatile unsigned char *)0x52000244)
+#define rEP3_DMA_FIFO		(*(volatile unsigned char *)0x52000248)
+#define rEP3_DMA_TX_LO		(*(volatile unsigned char *)0x5200024C)
+#define rEP3_DMA_TX_MD		(*(volatile unsigned char *)0x52000250)
+#define rEP3_DMA_TX_HI		(*(volatile unsigned char *)0x52000254)
+#define rEP4_DMA_CON		(*(volatile unsigned char *)0x52000258)
+#define rEP4_DMA_UNIT		(*(volatile unsigned char *)0x5200025C)
+#define rEP4_DMA_FIFO		(*(volatile unsigned char *)0x52000260)
+#define rEP4_DMA_TX_LO		(*(volatile unsigned char *)0x52000264)
+#define rEP4_DMA_TX_MD		(*(volatile unsigned char *)0x52000268)
+#define rEP4_DMA_TX_HI		(*(volatile unsigned char *)0x5200026C)
+#endif                          /*  __BIG_ENDIAN */
+
+/* WATCH DOG TIMER */
+#define rWTCON			(*(volatile unsigned *)0x53000000)
+#define rWTDAT			(*(volatile unsigned *)0x53000004)
+#define rWTCNT			(*(volatile unsigned *)0x53000008)
+
+/* IIC */
+#define rIICCON			(*(volatile unsigned *)0x54000000)
+#define rIICSTAT		(*(volatile unsigned *)0x54000004)
+#define rIICADD			(*(volatile unsigned *)0x54000008)
+#define rIICDS			(*(volatile unsigned *)0x5400000C)
+
+/* IIS */
+#define rIISCON			(*(volatile unsigned *)0x55000000)
+#define rIISMOD			(*(volatile unsigned *)0x55000004)
+#define rIISPSR			(*(volatile unsigned *)0x55000008)
+#define rIISFCON		(*(volatile unsigned *)0x5500000C)
+
+#ifdef __BIG_ENDIAN
+#define IISFIF			((volatile unsigned short *)0x55000012)
+#else                           /*  little endian */
+#define IISFIF			((volatile unsigned short *)0x55000010)
+#endif
+
+/* I/O PORT */
+#define rGPACON			(*(volatile unsigned *)0x56000000)
+#define rGPADAT			(*(volatile unsigned *)0x56000004)
+
+#define rGPBCON			(*(volatile unsigned *)0x56000010)
+#define rGPBDAT			(*(volatile unsigned *)0x56000014)
+#define rGPBUP			(*(volatile unsigned *)0x56000018)
+
+#define rGPCCON			(*(volatile unsigned *)0x56000020)
+#define rGPCDAT			(*(volatile unsigned *)0x56000024)
+#define rGPCUP			(*(volatile unsigned *)0x56000028)
+
+#define rGPDCON			(*(volatile unsigned *)0x56000030)
+#define rGPDDAT			(*(volatile unsigned *)0x56000034)
+#define rGPDUP			(*(volatile unsigned *)0x56000038)
+
+#define rGPECON			(*(volatile unsigned *)0x56000040)
+#define rGPEDAT			(*(volatile unsigned *)0x56000044)
+#define rGPEUP			(*(volatile unsigned *)0x56000048)
+
+#define rGPFCON			(*(volatile unsigned *)0x56000050)
+#define rGPFDAT			(*(volatile unsigned *)0x56000054)
+#define rGPFUP			(*(volatile unsigned *)0x56000058)
+
+#define rGPGCON			(*(volatile unsigned *)0x56000060)
+#define rGPGDAT			(*(volatile unsigned *)0x56000064)
+#define rGPGUP			(*(volatile unsigned *)0x56000068)
+
+#define rGPHCON			(*(volatile unsigned *)0x56000070)
+#define rGPHDAT			(*(volatile unsigned *)0x56000074)
+#define rGPHUP			(*(volatile unsigned *)0x56000078)
+
+#define rMISCCR			(*(volatile unsigned *)0x56000080)
+#define rDCLKCON		(*(volatile unsigned *)0x56000084)
+#define rEXTINT0		(*(volatile unsigned *)0x56000088)
+#define rEXTINT1		(*(volatile unsigned *)0x5600008C)
+#define rEXTINT2		(*(volatile unsigned *)0x56000090)
+#define rEINTFLT0		(*(volatile unsigned *)0x56000094)
+#define rEINTFLT1		(*(volatile unsigned *)0x56000098)
+#define rEINTFLT2		(*(volatile unsigned *)0x5600009C)
+#define rEINTFLT3		(*(volatile unsigned *)0x560000A0)
+#define rEINTMASK		(*(volatile unsigned *)0x560000A4)
+#define rEINTPEND		(*(volatile unsigned *)0x560000A8)
+#define rGSTATUS0		(*(volatile unsigned *)0x560000AC)
+#define rGSTATUS1		(*(volatile unsigned *)0x560000B0)
+
+/* RTC */
+#ifdef __BIG_ENDIAN
+#define rRTCCON			(*(volatile unsigned char *)0x57000043)
+#define rTICNT			(*(volatile unsigned char *)0x57000047)
+#define rRTCALM			(*(volatile unsigned char *)0x57000053)
+#define rALMSEC			(*(volatile unsigned char *)0x57000057)
+#define rALMMIN			(*(volatile unsigned char *)0x5700005B)
+#define rALMHOUR		(*(volatile unsigned char *)0x5700005F)
+#define rALMDATE		(*(volatile unsigned char *)0x57000063)
+#define rALMMON			(*(volatile unsigned char *)0x57000067)
+#define rALMYEAR		(*(volatile unsigned char *)0x5700006B)
+#define rRTCRST			(*(volatile unsigned char *)0x5700006F)
+#define rBCDSEC			(*(volatile unsigned char *)0x57000073)
+#define rBCDMIN			(*(volatile unsigned char *)0x57000077)
+#define rBCDHOUR		(*(volatile unsigned char *)0x5700007B)
+#define rBCDDATE		(*(volatile unsigned char *)0x5700007F)
+#define rBCDDAY			(*(volatile unsigned char *)0x57000083)
+#define rBCDMON			(*(volatile unsigned char *)0x57000087)
+#define rBCDYEAR		(*(volatile unsigned char *)0x5700008B)
+#else                           /*  little endian */
+#define rRTCCON			(*(volatile unsigned char *)0x57000040)
+#define rTICNT			(*(volatile unsigned char *)0x57000044)
+#define rRTCALM			(*(volatile unsigned char *)0x57000050)
+#define rALMSEC			(*(volatile unsigned char *)0x57000054)
+#define rALMMIN			(*(volatile unsigned char *)0x57000058)
+#define rALMHOUR		(*(volatile unsigned char *)0x5700005C)
+#define rALMDATE		(*(volatile unsigned char *)0x57000060)
+#define rALMMON			(*(volatile unsigned char *)0x57000064)
+#define rALMYEAR		(*(volatile unsigned char *)0x57000068)
+#define rRTCRST			(*(volatile unsigned char *)0x5700006C)
+#define rBCDSEC			(*(volatile unsigned char *)0x57000070)
+#define rBCDMIN			(*(volatile unsigned char *)0x57000074)
+#define rBCDHOUR		(*(volatile unsigned char *)0x57000078)
+#define rBCDDATE		(*(volatile unsigned char *)0x5700007C)
+#define rBCDDAY			(*(volatile unsigned char *)0x57000080)
+#define rBCDMON			(*(volatile unsigned char *)0x57000084)
+#define rBCDYEAR		(*(volatile unsigned char *)0x57000088)
+#endif
+
+/* ADC */
+#define rADCCON			(*(volatile unsigned *)0x58000000)
+#define rADCTSC			(*(volatile unsigned *)0x58000004)
+#define rADCDLY			(*(volatile unsigned *)0x58000008)
+#define rADCDAT0		(*(volatile unsigned *)0x5800000C)
+#define rADCDAT1		(*(volatile unsigned *)0x58000010)
+
+/* SPI */
+#define rSPCON0			(*(volatile unsigned *)0x59000000)
+#define rSPSTA0			(*(volatile unsigned *)0x59000004)
+#define rSPPIN0			(*(volatile unsigned *)0x59000008)
+#define rSPPRE0			(*(volatile unsigned *)0x5900000C)
+#define rSPTDAT0		(*(volatile unsigned *)0x59000010)
+#define rSPRDAT0		(*(volatile unsigned *)0x59000014)
+#define rSPCON1			(*(volatile unsigned *)0x59000020)
+#define rSPSTA1			(*(volatile unsigned *)0x59000024)
+#define rSPPIN1			(*(volatile unsigned *)0x59000028)
+#define rSPPRE1			(*(volatile unsigned *)0x5900002C)
+#define rSPTDAT1		(*(volatile unsigned *)0x59000030)
+#define rSPRDAT1		(*(volatile unsigned *)0x59000034)
+
+/* SD INTERFACE */
+#define rSDICON			(*(volatile unsigned *)0x5A000000)
+#define rSDIPRE			(*(volatile unsigned *)0x5A000004)
+#define rSDICmdArg		(*(volatile unsigned *)0x5A000008)
+#define rSDICmdCon		(*(volatile unsigned *)0x5A00000C)
+#define rSDICmdSta		(*(volatile unsigned *)0x5A000010)
+#define rSDIRSP0		(*(volatile unsigned *)0x5A000014)
+#define rSDIRSP1		(*(volatile unsigned *)0x5A000018)
+#define rSDIRSP2		(*(volatile unsigned *)0x5A00001C)
+#define rSDIRSP3		(*(volatile unsigned *)0x5A000020)
+#define rSDIDTimer		(*(volatile unsigned *)0x5A000024)
+#define rSDIBSize		(*(volatile unsigned *)0x5A000028)
+#define rSDIDatCon		(*(volatile unsigned *)0x5A00002C)
+#define rSDIDatCnt		(*(volatile unsigned *)0x5A000030)
+#define rSDIDatSta		(*(volatile unsigned *)0x5A000034)
+#define rSDIFSTA		(*(volatile unsigned *)0x5A000038)
+#ifdef __BIG_ENDIAN
+#define rSDIDAT			(*(volatile unsigned char *)0x5A00003F)
+#else
+#define rSDIDAT			(*(volatile unsigned char *)0x5A00003C)
+#endif
+#define rSDIIntMsk		(*(volatile unsigned *)0x5A000040)
+
+#endif
+
+#endif /*__S3C24X0_H__*/
diff --git a/linux-bsp/asm-study/myboot/interrupt.c b/linux-bsp/asm-study/myboot/interrupt.c
new file mode 100644
index 0000000..dbc9b7f
--- /dev/null
+++ b/linux-bsp/asm-study/myboot/interrupt.c
@@ -0,0 +1,39 @@
+/********************************************************************************************
+ *        File:  interrupt.c
+ *     Version:  1.0.0
+ *   Copyright:  2011 (c) Guo Wenxue <guowenxue@gmail.com>
+ * Description:  The CPU interrupt vector table depends on function, called in start.S 
+ *   ChangeLog:  1, Release initial version on "Tue Jul 12 16:43:18 CST 2011"
+ *
+ *******************************************************************************************/
+
+#include <common.h>
+
+void do_undefined_instruction(void)
+{
+
+}
+
+void do_software_interrupt(void)
+{
+}
+
+void do_prefetch_abort(void)
+{
+}
+
+void do_data_abort(void)
+{
+}
+
+void do_not_used(void)
+{
+}
+
+void do_irq(void)
+{
+}
+
+void do_fiq(void)
+{
+}
diff --git a/linux-bsp/asm-study/myboot/k9f2g08.c b/linux-bsp/asm-study/myboot/k9f2g08.c
new file mode 100644
index 0000000..b74813d
--- /dev/null
+++ b/linux-bsp/asm-study/myboot/k9f2g08.c
@@ -0,0 +1,638 @@
+/********************************************************************************************
+ *        File:  k9f2g08.c: K9F2G08 read/write/erase functions for bootstrap
+ *     Version:  1.0.0
+ *   Copyright:  2011 (c) Guo Wenxue <guowenxue@gmail.com>
+ * Description:  This C code is the first stage bootloader(named bootstrap) 
+                 main code, test on FL2440 board.
+ *   ChangeLog:  1, Release initial version on "Tue Jul 12 16:43:18 CST 2011"
+ *
+ *******************************************************************************************/
+
+
+/*************************************************************
+ * Read Status Register Definition of K9F2G08(Refer to k9f2g08u0m datasheet)
+ *  
+ * |-------------------------------------------------------------------------------------|
+ * | I/O No. | Page Program | Block Erase | Cache Program |     Read    | Definition     |
+ * |-------------------------------------------------------------------------------------|
+ * | I/O 0   |  Pass/Fail   |  Pass/Fail  | Pass/Fail(N)  |   Not use   | Pass:0 Fail:1  |
+ * |-------------------------------------------------------------------------------------|
+ * | I/O 1   |  Not use     |  Not use    | Pass/Fail(N-1)|   Not use   | Pass:0 Fail:1  |
+ * |-------------------------------------------------------------------------------------|
+ * | I/O 2   |  Not use     |  Not use    | Not use       |   Not use   | Don't care     |
+ * |-------------------------------------------------------------------------------------|
+ * | I/O 3   |  Not use     |  Not use    | Not use       |   Not use   | Don't care     |
+ * |-------------------------------------------------------------------------------------|
+ * | I/O 4   |  Not use     |  Not use    | Not use       |   Not use   | Don't care     |
+ * |-------------------------------------------------------------------------------------|
+ * | I/O 5   |  Ready/Busy  |  Ready/Busy |True Ready/Busy| Ready/Busy  | Busy:0 Ready:1 |
+ * |-------------------------------------------------------------------------------------|
+ * | I/O 6   |  Ready/Busy  |  Ready/Busy | Ready/Busy    | Ready/Busy  | Busy:0 Ready:1 |
+ * |-------------------------------------------------------------------------------------|
+ * | I/O 7   |Write protect |Write protect| Write protect |Write protect| Protect:0 Not:1|
+ * |-------------------------------------------------------------------------------------|
+ *
+ *************************************************************/
+
+#include <nand.h>
+
+/**
+ * nand_read_id - Read the Nandflash ID
+ * @nand:       The nand flash information
+ * return:      The nandflash ID
+ */
+static unsigned short nand_read_id(void)
+{
+    unsigned short id = 0;
+
+    nand_select(); /* chip Enable */
+    nand_clear_RnB(); /*Clear Ready & Busy signal*/
+
+    REG_NFCMD = NAND_CMD_READID; /*Read ID command*/
+    REG_NFADDR = 0x00;  /*Give address 0x00*/
+    id = REG_NFDATA;  /*First byte, Maker code: 0xEC->Samsung*/
+    id = (id << 8) | REG_NFDATA; /*Second byte, Device ID:0xDA->K9F2G08*/
+
+    /*We can read the followed 3 bytes(0x10,0x95,0x44) here, but it's useless.*/
+
+    nand_deselect();
+
+    return id;
+}
+
+#define TACLS       1    // 1-clk 
+#define TWRPH0      4    // 4-clk
+#define TWRPH1      1    // 1-clk  //TACLS+TWRPH0+TWRPH1>=50ns
+
+/**
+ * nand_init - Initial the Nandflash controller and nand flash information structure "nand"
+ * @nand:       The nand flash information
+ * Return:      0->success <0 failed
+ */
+int nand_init(struct boot_nand_t *nand)
+{
+    int i, ret = -1;
+    unsigned short nand_id;
+
+    /*TACL=1, TWRPH0=4, TWRPH1=1, bit[0]=0 means the Nandflash bit witdth is 8bit(K9F2G08 is 8bit)*/
+    REG_NFCONF= (TACLS<<12)|(TWRPH0<<8)|(TWRPH1<<4)|(0<<0);
+
+    /* 
+     * Bit[13:12]  No lock
+     * Bit[10:8]   No nandflash interrupt
+     * Bit[6:4]    Initialize ECC and lock data area & spare area ECC
+     * Bit[1]      Enable nand flash chip select
+     * Bit[0]      Enable nand flash controller
+     */
+    REG_NFCONT= (0<<13)|(0<<12)|(0<<10)|(0<<9)|(0<<8)|(1<<6)|(1<<5)|(1<<4)|(1<<1)|(1<<0);
+
+
+    for (i=0; i<10; i++) ;  /*Wait tWB(100ns)*/
+
+    nand_id = nand_read_id();
+
+    /*K9F2G08 page/read/write size is 2K bytes, spare size is 64 bytes 
+     * and block/erase size is 128K*/
+    if ( NAND_K9F2G08 == nand_id )  /* Samsung K9F2G08 */
+    {                         
+        /*1 Device = 2048 Blocks, 1 Block=64Pages, 1 Pages=(2K Bytes data+ 64Bytes spare)*/
+        nand->id = NAND_K9F2G08;
+        nand->spare_size = 64;    /* 64 bytes */
+        nand->page_size = 0x0800;    /* 1<<11=2K */
+        nand->block_size = 0x20000;  /* 1<<17=128K*/
+        nand->block_num = 2048;      /* 1<<17=128K*/
+        /*Bad block tag is the first byte in spare area*/
+        nand->bad_block_offset = nand->page_size; 
+        ret = 0;
+    }
+
+    return ret;
+}
+
+/**
+ * nand_read_page - Read the data from a page main data area 
+ * @nand:       The nand flash information
+ * @page_num:   The read page number
+ * @offset:     The read data start offset address in the page
+ * @size:       The request read data length
+ * @data:       The read data  output buffer
+ * Return:      >=0 read bytes
+ */
+int nand_read_page(struct boot_nand_t *nand, ulong page_num, ulong offset, char *data, ulong size)
+{
+    uchar  *ptr = (uchar *)data;
+    ulong  i, bytes;
+
+    /*Avoid the offset+size larger than a page size(include main data and spare data size) */
+    bytes = ((nand->page_size+nand->spare_size-offset)>=size ? size : (nand->page_size+nand->spare_size)-offset);
+
+    nand_select();
+    nand_clear_RnB();
+
+    REG_NFCMD = NAND_CMD_READ0;
+    /* Write Address */
+    REG_NFADDR = 0;
+    REG_NFADDR = 0;
+    REG_NFADDR = page_num & 0xff;
+    REG_NFADDR = (page_num >> 8) & 0xff;
+    REG_NFADDR = (page_num >> 16) & 0xff;
+    REG_NFCMD = NAND_CMD_READSTART;
+
+    /* 
+     * After give NAND_CMD_READSTART command, when the RnB get a rising edge signal, it 
+     * will set(Read S3C2440 datasheet about NFCONT register) the NFSTAT register bit[2] 
+     * in nandflash controller. After get this signal, then we can read the data or send  
+     * followed command
+     */
+    nand_detect_RnB();
+
+    /* If the offset address in the page is 0 and need read a whole page, 
+     * then we read the whole page, or use the random page read */
+    if(0==offset && nand->page_size==size)
+            goto START_READ;
+
+    /*Page Random Read will come here*/
+    REG_NFCMD = NAND_CMD_RNDOUT;
+    REG_NFADDR = offset & 0xff;
+    REG_NFADDR = (offset >> 8) & 0xff;
+    REG_NFCMD = NAND_CMD_RNDOUTSTART;
+
+START_READ:
+    for(i=0; i<bytes; i++)
+    {
+       *ptr = REG_NFDATA;
+        ptr++;
+    }
+
+    nand_deselect();
+    return bytes;
+}
+
+
+/**
+ * nand_write_page - Write the data to a page main data area 
+ * @nand:       The nand flash information
+ * @page_num:   The written page number
+ * @offset:     The written data start offset address in the page
+ * @size:       The written data length
+ * @data:       The written data 
+ * Return:      >=0 write bytes
+ */
+int nand_write_page(struct boot_nand_t *nand, ulong page_num, ulong offset, char *data, ulong size)
+{
+    uchar  *ptr8 = (uchar *)data;
+    uchar  stat;
+    int    ret;
+    ulong  i, bytes;
+
+    /*Avoid the offset+size larger than a page size(include main data and spare data size) */
+    bytes = ((nand->page_size+nand->spare_size-offset)>size ? size : (nand->page_size+nand->spare_size)-offset);
+
+    nand_select();
+    nand_clear_RnB();
+
+    REG_NFCMD = NAND_CMD_SEQIN;
+    /* Write Address */
+    REG_NFADDR = 0;
+    REG_NFADDR = 0;
+    REG_NFADDR = page_num & 0xff;
+    REG_NFADDR = (page_num >> 8) & 0xff;
+    REG_NFADDR = (page_num >> 16) & 0xff;
+
+    /* If the offset address in the page is 0 and need write a whole page data, 
+     * then we read the whole page, or use the random page program */
+    if(0==offset && nand->page_size==size)
+            goto START_PROG;
+
+    /*Random page program will come here*/
+    REG_NFCMD = NAND_CMD_RNDIN;
+    REG_NFADDR = offset & 0xff;
+    REG_NFADDR = (offset >> 8) & 0xff;
+
+START_PROG:
+    for(i=0; i<bytes; i++)
+    {
+        REG_NFDATA = *ptr8; 
+        ptr8++;
+    }
+    REG_NFCMD = NAND_CMD_PAGEPROG;
+
+    /* 
+     * After give NAND_CMD_PAGEPROG command, when the RnB get a rising edge signal, it 
+     * will set(Read S3C2440 datasheet about NFCONT register) the NFSTAT register bit[2] 
+     * in nandflash controller. After get this signal, then we can send followed command.
+     */
+    nand_detect_RnB();
+
+    /* When program operation is completed, the Write Status register Bit[I/O] 0 maybe checked, 
+     * bit[0]=0 means pass, or bit[0]=1 means Fail. Refer the top table definition  */
+    REG_NFCMD = NAND_CMD_STATUS;
+    stat = REG_NFDATA;
+    if(stat & 0x01)   
+    {
+        dbg_print("Random Program page number @%lu failure\n", page_num);
+        ret = -1; /*Program failure*/
+    }
+    else
+    {
+        ret = bytes; 
+    }
+
+    nand_deselect();
+    return ret;
+}
+
+
+/**
+ * is_bad_block - check the block which the "addr" in is valid or not
+ * @nand:  Nandflash information
+ * @addr:  The offset address in whole nandflash, no need block alignment
+ * Return: 1->bad block, 0->Valid block 
+ */
+int is_bad_block(struct boot_nand_t *nand, ulong addr)
+{
+    char data;
+    ulong page_num;
+    ulong block_start;
+    int  page_shift = generic_ffs(nand->page_size)-1;
+
+    /*Get start address of the block wherre the "addr" in*/
+    block_start = addr & (~(nand->block_size-1)); 
+
+    /* Get the first page number in the block, the Bad Block Tag is set in  
+     * the first bit in the first page spare area in the block */
+    page_num = block_start >> page_shift;     
+
+    nand_read_page(nand, page_num, nand->bad_block_offset, &data, 1);
+
+    if (data != 0xff)
+    {
+        printf("Bad Block @%08lx by address @%08lx\n",block_start, addr);
+        nand_deselect();
+        return 1;
+    }
+
+    nand_deselect();
+    return 0;
+}
+
+/**
+ * mark_bad_block - Mark the block as bad block
+ * @nand:  Nandflash information
+ * @addr:  The offset address in whole nandflash, no need block alignment
+ * Return: 0->mark bad block success, <0 mark bad block failed. 
+ */
+int mark_bad_block(struct boot_nand_t *nand, ulong addr)
+{
+    char data = 0xEE;
+    ulong page_num;
+    ulong block_num;
+    ulong block_start;
+    int  ret;
+
+    /*Get start address of the block wherre the "addr" in*/
+    block_start = addr & (~(nand->block_size-1)); 
+
+    /* Get the first page number in the block, the Bad Block Tag is set in  
+     * the first bit in the first page spare area in the block */
+    page_num = block_start >> (generic_ffs(nand->page_size)-1);     
+
+
+    ret = nand_write_page(nand, page_num, nand->bad_block_offset, &data, 1);
+    ret = ret<0 ? ret: 0;
+
+    block_num = block_start >> (generic_ffs(nand->block_size)-1);     
+    dbg_print("Mark  bad block index [$%lu] address @0x%08lx %s.\n", 
+                    block_num, block_start, ret==0?"success":"failed");
+    return ret;
+}
+
+/**
+ * nand_erase_block - Erase a block specify by the block_num
+ * @nand:       Nandflash information
+ * @block_num:  The erase block index number
+ * Return:      0->success, <0  Failure
+ */
+
+int nand_erase_block(struct boot_nand_t *nand, ulong block_num) 
+{
+    uchar   stat;
+    int     ret = 0;
+    ulong   block_start; /*Block start address*/
+
+    nand_select(); 
+    nand_clear_RnB();
+
+    REG_NFCMD = NAND_CMD_ERASE1; 
+    REG_NFADDR = (block_num<<6) & 0xff;     /*Row address A18~A19*/
+    REG_NFADDR = (block_num>>2) & 0xff;     /*Row address A20~A27*/
+    REG_NFADDR = (block_num>>10) & 0x0f;    /*Row address A28*/
+    REG_NFCMD = NAND_CMD_ERASE2; 
+
+   /* 
+    * After give NAND_CMD_ERASE2 command, when the RnB get a rising edge signal, it 
+    * will set(Read S3C2440 datasheet about NFCONT register) the NFSTAT register bit[2] 
+    * in nandflash controller. After get this signal, then we can send next command.
+    */
+    nand_detect_RnB();
+
+   /* When erase operation is completed, the Write Status register Bit[I/O] 0 maybe checked, 
+    * bit[0]=0 means pass, or bit[0]=1 means Fail. Refer the top table definition  */
+    REG_NFCMD = NAND_CMD_STATUS;
+
+    stat = REG_NFDATA;
+
+    block_start = block_num<<(generic_ffs(nand->block_size)-1);
+    if( stat&(1<<0) )
+    {
+         printf("Erase block index [$%lu] address @0x%08lx failed.\n", block_num, block_start);
+         mark_bad_block(nand, block_start);
+         ret = -1;
+         goto OUT;
+    }
+
+    dbg_print("Erase block index [$%lu] address @0x%08lx success.\n", block_num, block_start);
+
+OUT:
+    nand_deselect();
+    return ret;
+}
+
+
+/**
+ * nand_erase - Erase some blocks from start_addr
+ * @nand:        Nandflash information
+ * @start_addr:  The erase start address, it must be aligment 
+ * @size:        The erase block size, it must be  n*block_size
+ * @skip_bad:    Whether need auto skip the bad block or not, if skip, the erase size don't change
+ * Return:       0->success, >0 Bad block count
+ */
+int nand_erase(struct boot_nand_t *nand, ulong start_addr, ulong size, int skip_bad)
+{
+
+    int     block_num, ret=0;
+    int     failed = 0;
+    ulong   addr;
+    int     block_shift = generic_ffs(nand->block_size)-1;
+
+    if ( (start_addr & (nand->block_size-1)) || (size & (nand->block_size-1)) )
+    {
+        printf("nand erase address @0x%08lx or size $%lu not block aligment.\n", start_addr, size);
+        return -1;       /* invalid alignment */
+    }
+
+    addr = start_addr;
+    while( addr<(start_addr+size) )
+    {
+        block_num = addr>> block_shift;
+        ret = nand_erase_block(nand, block_num);
+        if(ret < 0)
+        {
+            if(skip_bad)      
+            {
+                /*Erase next block*/
+                addr += nand->block_size; 
+                size += nand->block_size; 
+                continue;
+            }
+            else
+            {
+                failed ++;
+            }
+        }
+        else
+            addr += nand->block_size;
+    }
+
+    /*If don't skip the bad block, then return the erase block failure times, or return OK.*/
+    ret = (!skip_bad && failed) ? failed :  0;
+
+    return ret;    
+}
+
+/*
+ * nand_scrub - nand erase the whole Nandflash
+ * @nand:       The nand flash information
+ */
+void nand_scrub(struct boot_nand_t *nand)
+{
+    int i;
+
+    for(i=0; i<nand->block_num; i++)
+       nand_erase_block(nand, i);
+}
+
+/* nand_read_spare - Read some bytes from the spare first byte
+ * @nand:       The nand flash information
+ * @page_addr:  The page address in the whole Nand flash, no need page alignment
+ * @size:       The spare area request read size, which start from the spare first byte
+ * @buf:        The output data buffer
+ * Return:      Read spare area data bytes
+ */
+int nand_read_spare(struct boot_nand_t *nand, ulong page_addr, int size, char *buf)
+{
+    ulong page_num;
+    ulong bytes;
+    int  page_shift = generic_ffs(nand->page_size)-1;
+
+    size = size > nand->spare_size ? nand->spare_size : size;
+
+    page_num = page_addr >> page_shift;   /*The page number in the whole Nandflash*/
+
+    bytes = nand_read_page(nand, page_num, nand->bad_block_offset, buf, size);
+
+    return bytes;
+}
+
+/* nand_write_spare - Write some bytes to the spare first byte
+ * @nand:       The nand flash information
+ * @page_addr:  The page address in the whole Nand flash, no need page alignment
+ * @size:       The write data size
+ * @buf:        The write data
+ * Return:      Write to spare area data bytes
+ */
+int nand_write_spare(struct boot_nand_t *nand, ulong page_addr, int size, char *buf)
+{
+    ulong page_num;
+    ulong bytes;
+    int  page_shift = generic_ffs(nand->page_size)-1;
+
+    size = size > nand->spare_size ? nand->spare_size : size;
+
+    page_num = page_addr >> page_shift;   /*The page number in the whole Nandflash*/
+
+    bytes = nand_write_page(nand, page_num, nand->bad_block_offset, buf, size);
+
+    return bytes;
+}
+
+/**
+ * nand_read -   Read some datas in the main data area in the page
+ * @nand:        Nandflash information
+ * @start_addr:  The read start address, it must be page alignment 
+ * @size:        The request read data size, no need alignment
+ * @buf:         The read data output buffer
+ * Return:       >=0 Read data bytes,  <0 Read failure
+ */
+int nand_read(struct boot_nand_t *nand, ulong start_addr, ulong size, char *buf)
+{
+    ulong addr;
+    ulong page_num;
+    ulong page_offset;
+    ulong page_mask = nand->page_size-1;
+    ulong bytes = 0;
+    ulong left;
+    int  page_shift = generic_ffs(nand->page_size)-1;
+
+    left = size;
+    addr = start_addr;
+
+    /* The address must be page alignment*/
+    if( (addr & page_mask) )
+    {
+          printf("nand read address @0x%08lx not alignment.\n", addr);
+          return -1;  
+    }
+
+    while(left > 0)
+    {
+         /*If the addr is block alignment, then we check this block is valid or not*/
+         if ( ((addr&(nand->block_size-1))==0) && is_bad_block(nand, addr) )   
+         {
+                /*Skip Bad block and goto next block */
+                dbg_print("Skip bad block @0x%08lx\n", addr);
+                addr += nand->block_size;
+                continue;
+         }
+
+         page_num = addr >> page_shift;   /*The page number in the whole Nandflash*/
+         page_offset = addr & page_mask;     /*The offset address in the page*/
+
+         if( left >= nand->page_size)
+         {
+             bytes = nand_read_page(nand, page_num, page_offset, buf, nand->page_size);
+#if 1
+             dbg_print("Read whole page: addr=%08lx page_num=%d page_offset=%08lx, bytes=%lu \n", 
+                             addr, page_num, page_offset, bytes);
+#endif
+         }
+         else
+         {
+             bytes = nand_read_page(nand, page_num, page_offset, buf, size%nand->page_size);
+#if 1
+             printf("Read part page: addr=%08lx page_num=%d page_offset=%d, bytes=%lu \n", 
+                             addr, page_num, page_offset, size%nand->page_size);
+#endif
+         }
+
+         addr+=bytes;
+         buf += bytes;
+         left-=bytes;
+    }
+
+    return bytes;
+}
+
+
+/**
+ * nand_write -  Write some datas to the main data area in the page
+ * @nand:        Nandflash information
+ * @start_addr:  The write start address, it must be page alignment 
+ * @size:        The write data size, no need alignment
+ * @buf:         The write data 
+ * Return:       >=0 Write data bytes,  <0 Write failure
+ */
+int nand_write(struct boot_nand_t *nand, ulong start_addr, ulong size, char *buf)
+{
+    ulong addr;
+    ulong page_num;
+    ulong page_offset;
+    ulong page_mask = nand->page_size-1;
+    ulong bytes = 0;
+    ulong left;
+    int  page_shift = generic_ffs(nand->page_size)-1;
+
+    left = size;
+    addr = start_addr;
+
+    /* The address must be page alignment*/
+    if( (addr & page_mask) )
+    {
+          printf("nand read address @0x%08lx not alignment.\n", addr);
+          return -1;  
+    }
+
+    while(left > 0)
+    {
+         /*If the addr is block alignment, then we check this block is valid or not*/
+         if ( ((addr&(nand->block_size-1))==0) && is_bad_block(nand, addr) )   
+         {
+                /*Skip Bad block and goto next block */
+                dbg_print("Skip bad block @0x%08lx\n", addr);
+                addr += nand->block_size;
+                continue;
+         }
+
+         page_num = addr >> page_shift;   /*The page number in the whole Nandflash*/
+         page_offset = addr & page_mask;     /*The offset address in the page*/
+
+         if( left >= nand->page_size)
+         {
+             bytes = nand_write_page(nand, page_num, page_offset, buf, nand->page_size);
+#if 1
+             dbg_print("Write whole page: addr=%08lx page_num=%d page_offset=%08lx, bytes=%lu \n", 
+                             addr, page_num, page_offset, bytes);
+#endif
+         }
+         else
+         {
+             bytes = nand_write_page(nand, page_num, page_offset, buf, size%nand->page_size);
+#if 1
+             dbg_print("Write part page: addr=%08lx page_num=%d page_offset=%d, bytes=%lu \n", 
+                             addr, page_num, page_offset, size%nand->page_size);
+#endif
+         }
+
+         addr+=bytes;
+         buf += bytes;
+         left-=bytes;
+    }
+
+    return bytes;
+}
+
+
+#if 0
+
+/**
+ * nand_wait - wait Nandflash goes to Ready to operate
+ */
+static inline void nand_wait(void)
+{
+    int i;
+
+    /*NFSTAG register bit[0] is RnB:  0->Nandflash Busy  1->Nandflash Ready to operate */
+    while (!(REG_NFSTAT & NFSTAT_BUSY))  /*bit[0]*/
+    {
+        dbg_print("Nandflash is busy.\n");
+        for (i = 0; i < 10; i++) ;
+    }
+}
+
+
+/**
+ * nand_reset - Reset the Nandflash 
+ */
+static void nand_reset(void)
+{
+    nand_select(); /* chip Enable */
+    nand_clear_RnB(); /*Clear Ready & Busy signal*/
+
+    REG_NFCMD = NAND_CMD_RESET; /*Read ID command*/
+    REG_NFADDR = 0x00;  /*Give address 0x00*/
+
+    nand_detect_RnB();
+    nand_deselect();
+}
+#endif
+
diff --git a/linux-bsp/asm-study/myboot/led_beep.c b/linux-bsp/asm-study/myboot/led_beep.c
new file mode 100644
index 0000000..64baba3
--- /dev/null
+++ b/linux-bsp/asm-study/myboot/led_beep.c
@@ -0,0 +1,56 @@
+/********************************************************************************************
+ *        File:  led_beep.c
+ *     Version:  1.0.0
+ *   Copyright:  2011 (c) Guo Wenxue <guowenxue@gmail.com>
+ * Description:  LED & Beep operate funciton.
+ *   ChangeLog:  1, Release initial version on "Tue Jul 12 16:43:18 CST 2011"
+ *
+ *******************************************************************************************/
+
+#include <common.h>
+#define DELAY_TIME   1000000
+
+/*LED & Beep */
+#define GPBCON   (*(unsigned long volatile *)0x56000010)
+#define GPBDAT   (*(unsigned long volatile *)0x56000014)
+#define GPBUP    (*(unsigned long volatile *)0x56000018)
+
+inline void delay(unsigned long loops)
+{
+    __asm__ volatile ("1:\n" "subs %0, %1, #1\n" "bne 1b":"=r" (loops):"0"(loops));
+}
+
+void init_led_beep(void)
+{
+    /*  Set GPB5,GPB6,GPB8,GPB10 as GPIO mode(0x01) */
+    GPBCON = (GPBCON | 0x333C03) & 0x111401;
+    GPBUP = (GPBUP | 0x560);
+    /* Set GPB5,GPB6,GPB8,GPB10 as high level, to turn LED0,LED1,LED2,LED3 off */
+    GPBDAT = (GPBDAT | 0x560);
+}
+
+void turn_led_on(int led)
+{
+    GPBDAT = (GPBDAT & (~(1 << led)));
+    delay(DELAY_TIME);
+}
+
+void turn_led_off(int led)
+{
+    /* Turn LED0 on */
+    GPBDAT = (GPBDAT | (1 << led));
+    delay(DELAY_TIME);
+}
+
+void beep(int count)
+{
+    int i;
+    for (i = 0; i < count; i++)
+    {
+        GPBDAT |= 1 << BEEP;    /* Set Beep GPIO as high level */
+        delay(DELAY_TIME * 50);
+
+        GPBDAT &= ~(1 << BEEP); /* Set Beep GPIO as low level */
+        delay(DELAY_TIME * 50);
+    }
+}
diff --git a/linux-bsp/asm-study/myboot/makefile b/linux-bsp/asm-study/myboot/makefile
new file mode 100644
index 0000000..61ce521
--- /dev/null
+++ b/linux-bsp/asm-study/myboot/makefile
@@ -0,0 +1,118 @@
+
+# ***********************************************************************
+# *        File:  makefile
+# *     Version:  1.0.0
+# *   Copyright:  2011 (c) Guo Wenxue <guowenxue@gmail.com>
+# * Description:  Makefile used to cross compile the ASM source code
+# *   ChangeLog:  1, Release initial version on "Sun Mar 20 18:41:04 CST 2011"
+# *
+# ***********************************************************************
+#
+
+APP_NAME=bootstrap
+#INST_PATH=/tftp
+
+# Enable "printf" function for help, don't enable it for production to save about 2K size
+CONFIG_PRINTF_DBG=y
+
+# When wanna burn the image to nandflash and start from it, then commont follow option
+RAM_DEBUG=y
+
+BOARD=SMDK2440
+#BOARD=SMDK2416
+
+export BOARD
+
+SRC_TOP=$(CURDIR)
+
+CFLAGS+=-I${SRC_TOP}/include 
+CFLAGS+=-Os -D__KERNEL__ -DCONFIG_ARM -D__ARM__ -DBOARD_$(BOARD)
+PLATFORM_LIBS += -L $(shell dirname `$(CC) $(CFLAGS) -print-libgcc-file-name`) -lgcc
+
+ifeq ($(BOARD),SMDK2440)
+  PLATFORM_LIBS += -lc -L/opt/buildroot-2011.11/arm920t/usr/arm-unknown-linux-uclibcgnueabi/sysroot/usr/lib/
+  ifeq ($(RAM_DEBUG),y)
+       TEXT_BASE=0x33000000
+  else
+       TEXT_BASE=0x00000000
+  endif
+# Set the stack top base address here
+CFLAGS+=-DTEXT_BASE=$(TEXT_BASE) -DSTACK_BASE=0x33000000
+CROSS_COMPILE=/opt/xtools/arm920t/bin/arm-linux-
+CFLAGS+= -fno-strict-aliasing  -fno-common -ffixed-r8 -msoft-float 
+CFLAGS+=-march=armv4t -Wall -Wstrict-prototypes -fno-stack-protector
+endif
+
+ifeq ($(BOARD),SMDK2416)
+TEXT_BASE=0x33000000
+CFLAGS+=-DTEXT_BASE=$(TEXT_BASE)
+CROSS_COMPILE=/opt/buildroot-2011.11/arm926t/usr/bin/arm-linux-
+CFLAGS+= -fno-strict-aliasing  -fno-common -ffixed-r8 -msoft-float -mfloat-abi=soft
+CFLAGS+=-march=armv4t -Wstrict-prototypes -fno-stack-protector
+endif
+
+AS  = $(CROSS_COMPILE)as
+LD  = $(CROSS_COMPILE)ld
+CC  = $(CROSS_COMPILE)gcc
+CPP = $(CC) -E
+AR  = $(CROSS_COMPILE)ar
+NM  = $(CROSS_COMPILE)nm
+LDR = $(CROSS_COMPILE)ldr
+STRIP   = $(CROSS_COMPILE)strip
+OBJCOPY = $(CROSS_COMPILE)objcopy
+OBJDUMP = $(CROSS_COMPILE)objdump
+RANLIB  = $(CROSS_COMPILE)RANLIB
+
+gccincdir := $(shell $(CC) -print-file-name=include)
+CFLAGS += -ffreestanding -nostdinc -isystem $(gccincdir) -pipe 
+
+CFLAGS += -fno-builtin  
+LDFLAGS=-Bstatic -T$(APP_NAME).lds -Ttext $(TEXT_BASE)
+AFLAGS := $(CFLAGS) -D__ASSEMBLY__
+
+export  CROSS_COMPILE AS LD CC CPP AR NM STRIP OBJCOPY OBJDUMP CFLAGS
+
+SOBJS   := start.o mem_init.o
+OBJS    := bootstrap.o led_beep.o interrupt.o serial.o common.o xmodem.o k9f2g08.o 
+
+ifeq ($(CONFIG_PRINTF_DBG), y)
+CFLAGS+=-DCONFIG_PRINTF_DBG
+endif
+
+ALL: .depend $(SOBJS) $(OBJS)
+	cd $(SRC_TOP) 
+	${LD} $(LDFLAGS) $(SOBJS) \
+	--start-group $(OBJS) \
+	--end-group $(PLATFORM_LIBS) \
+	-Map $(APP_NAME).map  -o $(APP_NAME).elf
+	${OBJCOPY} -O binary $(APP_NAME).elf $(APP_NAME).bin
+	@chmod 777 $(APP_NAME).bin
+	@rm -f *.elf *.o
+
+.depend:    makefile $(SOBJS:.o=.S) $(OBJS:.o=.c)
+	$(CC) -M $(AFLAGS) -D__ASSEMBLY__ $(SOBJS:.o=.S) > $@ 
+	$(CC) -M $(CFLAGS) $(OBJS:.o=.c) > $@
+
+sinclude .depend
+
+%.o: %.S
+	 $(CC) $(AFLAGS) -c -o $@ $<
+%.o: %.c
+	 $(CC) $(CFLAGS) -c -o $@ $<
+
+install: $(APP_NAME).bin
+	cp $(APP_NAME).bin $(INST_PATH) -f 
+	cp $(APP_NAME).bin /tftp -f
+
+clean:
+	@find $(OBJTREE) -type f \
+			\( -name 'core' -o -name '*.bak' -o -name '*~' -o -name .depend \
+			-o -name '*.o'  -o -name '*.a' -o -name '*.elf' \) -print \
+			| xargs rm -f
+	@rm -f $(APP_NAME).bin
+	@rm -f $(APP_NAME).map
+
+distclean clear: clean
+	@rm -f cscope.* tags
+
+
diff --git a/linux-bsp/asm-study/myboot/mem_init.S b/linux-bsp/asm-study/myboot/mem_init.S
new file mode 100644
index 0000000..ddcce07
--- /dev/null
+++ b/linux-bsp/asm-study/myboot/mem_init.S
@@ -0,0 +1,170 @@
+/*
+ * Memory Setup stuff - taken from blob memsetup.S
+ *
+ * Copyright (C) 1999 2000 2001 Erik Mouw (J.A.K.Mouw@its.tudelft.nl) and
+ *                     Jan-Derk Bakker (J.D.Bakker@its.tudelft.nl)
+ *
+ * Modified for the Samsung SMDK2410 by
+ * (C) Copyright 2002
+ * David Mueller, ELSOFT AG, <d.mueller@elsoft.ch>
+ *
+ * Modified for the friendly-arm SBC-2410X by
+ * (C) Copyright 2005
+ * JinHua Luo, GuangDong Linux Center, <luo.jinhua@gd-linux.com>
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+/*
+ * Taken from linux/arch/arm/boot/compressed/head-s3c2410.S
+ *
+ * Copyright (C) 2002 Samsung Electronics SW.LEE  <hitchcar@sec.samsung.com>
+ */
+
+#include <config.h>
+
+#define BWSCON	0x48000000
+
+/* BWSCON */
+#define DW8			(0x0)
+#define DW16			(0x1)
+#define DW32			(0x2)
+#define WAIT			(0x1<<2)
+#define UBLB			(0x1<<3)
+
+#define B1_BWSCON		(DW16)
+#define B2_BWSCON		(DW16)
+#define B3_BWSCON		(DW16 + WAIT + UBLB)
+#define B4_BWSCON		(DW16)
+#define B5_BWSCON		(DW16)
+#define B6_BWSCON		(DW32)
+#define B7_BWSCON		(DW32)
+
+#define B0_Tacs			0x0
+#define B0_Tcos			0x0
+#define B0_Tacc			0x7
+#define B0_Tcoh			0x0
+#define B0_Tah			0x0
+#define B0_Tacp			0x0
+#define B0_PMC			0x0
+
+#define B1_Tacs			0x0
+#define B1_Tcos			0x0
+#define B1_Tacc			0x7
+#define B1_Tcoh			0x0
+#define B1_Tah			0x0
+#define B1_Tacp			0x0
+#define B1_PMC			0x0
+
+#define B2_Tacs			0x0
+#define B2_Tcos			0x0
+#define B2_Tacc			0x7
+#define B2_Tcoh			0x0
+#define B2_Tah			0x0
+#define B2_Tacp			0x0
+#define B2_PMC			0x0
+
+#define B3_Tacs			0xc
+#define B3_Tcos			0x7
+#define B3_Tacc			0xf
+#define B3_Tcoh			0x1
+#define B3_Tah			0x0
+#define B3_Tacp			0x0
+#define B3_PMC			0x0
+
+#define B4_Tacs			0x0
+#define B4_Tcos			0x0
+#define B4_Tacc			0x7
+#define B4_Tcoh			0x0
+#define B4_Tah			0x0
+#define B4_Tacp			0x0
+#define B4_PMC			0x0
+
+#define B5_Tacs			0xc
+#define B5_Tcos			0x7
+#define B5_Tacc			0xf
+#define B5_Tcoh			0x1
+#define B5_Tah			0x0
+#define B5_Tacp			0x0
+#define B5_PMC			0x0
+
+#define B6_MT			0x3	/* SDRAM */
+#define B6_Trcd			0x1
+#define B6_SCAN			0x1	/* 9bit */
+
+#define B7_MT			0x3	/* SDRAM */
+#define B7_Trcd			0x1	/* 3clk */
+#define B7_SCAN			0x1	/* 9bit */
+
+/* REFRESH parameter */
+#define REFEN			0x1	/* Refresh enable */
+#define TREFMD			0x0	/* CBR(CAS before RAS)/Auto refresh */
+#define Trc			0x3	/* 7clk */
+#define Tchr			0x2	/* 3clk */
+
+#if defined(CONFIG_S3C2440)
+#define Trp         0x2 /* 4clk */
+#define REFCNT          1012
+#else
+#define Trp         0x0 /* 2clk */
+#define REFCNT			0x0459
+#endif
+/**************************************/
+
+_TEXT_BASE:
+	.word	TEXT_BASE
+
+.globl mem_init
+mem_init:
+	/* memory control configuration */
+	/* make r0 relative the current location so that it */
+	/* reads SMRDATA out of FLASH rather than memory ! */
+	ldr     r0, =SMRDATA
+    ldr r1, =mem_init
+	sub	r0, r0, r1
+    adr r3, mem_init       /* r3 <- current position of code   */
+    add     r0, r0, r3
+	ldr	r1, =BWSCON	/* Bus Width Status Controller */
+	add     r2, r0, #13*4
+0:
+	ldr     r3, [r0], #4
+	str     r3, [r1], #4
+	cmp     r2, r0
+	bne     0b
+
+	/* everything is fine now */
+	mov	pc, lr
+
+	.ltorg
+/* the literal pools origin */
+
+SMRDATA:
+    .word (0+(B1_BWSCON<<4)+(B2_BWSCON<<8)+(B3_BWSCON<<12)+(B4_BWSCON<<16)+(B5_BWSCON<<20)+(B6_BWSCON<<24)+(B7_BWSCON<<28))
+    .word ((B0_Tacs<<13)+(B0_Tcos<<11)+(B0_Tacc<<8)+(B0_Tcoh<<6)+(B0_Tah<<4)+(B0_Tacp<<2)+(B0_PMC))
+    .word ((B1_Tacs<<13)+(B1_Tcos<<11)+(B1_Tacc<<8)+(B1_Tcoh<<6)+(B1_Tah<<4)+(B1_Tacp<<2)+(B1_PMC))
+    .word ((B2_Tacs<<13)+(B2_Tcos<<11)+(B2_Tacc<<8)+(B2_Tcoh<<6)+(B2_Tah<<4)+(B2_Tacp<<2)+(B2_PMC))
+    .word ((B3_Tacs<<13)+(B3_Tcos<<11)+(B3_Tacc<<8)+(B3_Tcoh<<6)+(B3_Tah<<4)+(B3_Tacp<<2)+(B3_PMC))
+    .word ((B4_Tacs<<13)+(B4_Tcos<<11)+(B4_Tacc<<8)+(B4_Tcoh<<6)+(B4_Tah<<4)+(B4_Tacp<<2)+(B4_PMC))
+    .word ((B5_Tacs<<13)+(B5_Tcos<<11)+(B5_Tacc<<8)+(B5_Tcoh<<6)+(B5_Tah<<4)+(B5_Tacp<<2)+(B5_PMC))
+    .word ((B6_MT<<15)+(B6_Trcd<<2)+(B6_SCAN))
+    .word ((B7_MT<<15)+(B7_Trcd<<2)+(B7_SCAN))
+    .word ((REFEN<<23)+(TREFMD<<22)+(Trp<<20)+(Trc<<18)+(Tchr<<16)+REFCNT)
+    .word 0xb2
+    .word 0x30
+    .word 0x30
diff --git a/linux-bsp/asm-study/myboot/nand.h b/linux-bsp/asm-study/myboot/nand.h
new file mode 100644
index 0000000..9269296
--- /dev/null
+++ b/linux-bsp/asm-study/myboot/nand.h
@@ -0,0 +1,271 @@
+/*
+ *  linux/include/linux/mtd/nand.h
+ *
+ *  Copyright (c) 2000 David Woodhouse <dwmw2@infradead.org>
+ *                     Steven J. Hill <sjhill@realitydiluted.com>
+ *		       Thomas Gleixner <tglx@linutronix.de>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Info:
+ *	Contains standard defines and IDs for NAND flash devices
+ *
+ * Changelog:
+ *	See git changelog.
+ */
+#ifndef __LINUX_MTD_NAND_H
+#define __LINUX_MTD_NAND_H
+
+#include <common.h>
+#include <linux/bitops.h>
+
+#define NAND_K9F2G08      0xecda
+
+/* This constant declares the max. oobsize / page, which
+ * is supported now. If you add a chip with bigger oobsize/page
+ * adjust this accordingly.
+ */
+#define NAND_MAX_OOBSIZE	218
+#define NAND_MAX_PAGESIZE	4096
+
+/*
+ * Constants for hardware specific CLE/ALE/NCE function
+ *
+ * These are bits which can be or'ed to set/clear multiple
+ * bits in one go.
+ */
+/* Select the chip by setting nCE to low */
+#define NAND_NCE		0x01
+/* Select the command latch by setting CLE to high */
+#define NAND_CLE		0x02
+/* Select the address latch by setting ALE to high */
+#define NAND_ALE		0x04
+
+#define NAND_CTRL_CLE		(NAND_NCE | NAND_CLE)
+#define NAND_CTRL_ALE		(NAND_NCE | NAND_ALE)
+#define NAND_CTRL_CHANGE	0x80
+
+/*
+ * Standard NAND flash commands
+ */
+#define NAND_CMD_READ0		0x00        /*Page read period 1*/
+#define NAND_CMD_READSTART	0x30        /*Page read period 2, for large page*/
+#define NAND_CMD_READID		0x90        /*Read production ID*/
+#define NAND_CMD_SEQIN		0x80        /*Page write period 1*/
+#define NAND_CMD_PAGEPROG	0x10        /*Page write period 2*/
+#define NAND_CMD_ERASE1		0x60        /*Block erase period 1*/
+#define NAND_CMD_ERASE2		0xd0        /*Block erase period 2*/
+#define NAND_CMD_STATUS		0x70        /*Read status command*/
+#define NAND_CMD_RESET		0xff        /*Nandflash reset command*/
+#define NAND_CMD_READ1		1
+#define NAND_CMD_RNDOUT		0x05        /*Page random read period 1*/
+#define NAND_CMD_RNDOUTSTART	0xE0    /*Page random read period 2*/
+#define NAND_CMD_RNDIN		0x85        /*Page random write*/
+
+#define NAND_CMD_READOOB	0x50
+#define NAND_CMD_STATUS_MULTI	0x71
+
+/* Extended commands for large page devices */
+#define NAND_CMD_CACHEDPROG	0x15
+
+/* Extended commands for AG-AND device */
+/*
+ * Note: the command for NAND_CMD_DEPLETE1 is really 0x00 but
+ *       there is no way to distinguish that from NAND_CMD_READ0
+ *       until the remaining sequence of commands has been completed
+ *       so add a high order bit and mask it off in the command.
+ */
+#define NAND_CMD_DEPLETE1	0x100
+#define NAND_CMD_DEPLETE2	0x38
+#define NAND_CMD_STATUS_MULTI	0x71
+#define NAND_CMD_STATUS_ERROR	0x72
+/* multi-bank error status (banks 0-3) */
+#define NAND_CMD_STATUS_ERROR0	0x73
+#define NAND_CMD_STATUS_ERROR1	0x74
+#define NAND_CMD_STATUS_ERROR2	0x75
+#define NAND_CMD_STATUS_ERROR3	0x76
+#define NAND_CMD_STATUS_RESET	0x7f
+#define NAND_CMD_STATUS_CLEAR	0xff
+
+#define NAND_CMD_NONE		-1
+
+/* Status bits */
+#define NAND_STATUS_FAIL	0x01
+#define NAND_STATUS_FAIL_N1	0x02
+#define NAND_STATUS_TRUE_READY	0x20
+#define NAND_STATUS_READY	0x40
+#define NAND_STATUS_WP		0x80
+
+/*
+ * Constants for ECC_MODES
+ */
+typedef enum
+{
+    NAND_ECC_NONE,
+    NAND_ECC_SOFT,
+    NAND_ECC_HW,
+    NAND_ECC_HW_SYNDROME,
+    NAND_ECC_HW_OOB_FIRST,
+} nand_ecc_modes_t;
+
+/*
+ * Constants for Hardware ECC
+ */
+/* Reset Hardware ECC for read */
+#define NAND_ECC_READ		0
+/* Reset Hardware ECC for write */
+#define NAND_ECC_WRITE		1
+/* Enable Hardware ECC before syndrom is read back from flash */
+#define NAND_ECC_READSYN	2
+
+/* Bit mask for flags passed to do_nand_read_ecc */
+#define NAND_GET_DEVICE		0x80
+
+/* Option constants for bizarre disfunctionality and real
+*  features
+*/
+/* Chip can not auto increment pages */
+#define NAND_NO_AUTOINCR	0x00000001
+/* Buswitdh is 16 bit */
+#define NAND_BUSWIDTH_16	0x00000002
+/* Device supports partial programming without padding */
+#define NAND_NO_PADDING		0x00000004
+/* Chip has cache program function */
+#define NAND_CACHEPRG		0x00000008
+/* Chip has copy back function */
+#define NAND_COPYBACK		0x00000010
+/* AND Chip which has 4 banks and a confusing page / block
+ * assignment. See Renesas datasheet for further information */
+#define NAND_IS_AND		0x00000020
+/* Chip has a array of 4 pages which can be read without
+ * additional ready /busy waits */
+#define NAND_4PAGE_ARRAY	0x00000040
+/* Chip requires that BBT is periodically rewritten to prevent
+ * bits from adjacent blocks from 'leaking' in altering data.
+ * This happens with the Renesas AG-AND chips, possibly others.  */
+#define BBT_AUTO_REFRESH	0x00000080
+/* Chip does not require ready check on read. True
+ * for all large page devices, as they do not support
+ * autoincrement.*/
+#define NAND_NO_READRDY		0x00000100
+/* Chip does not allow subpage writes */
+#define NAND_NO_SUBPAGE_WRITE	0x00000200
+
+/* Options valid for Samsung large page devices */
+#define NAND_SAMSUNG_LP_OPTIONS \
+	(NAND_NO_PADDING | NAND_CACHEPRG | NAND_COPYBACK)
+
+/* Macros to identify the above */
+#define NAND_CANAUTOINCR(chip) (!(chip->options & NAND_NO_AUTOINCR))
+#define NAND_MUST_PAD(chip) (!(chip->options & NAND_NO_PADDING))
+#define NAND_HAS_CACHEPROG(chip) ((chip->options & NAND_CACHEPRG))
+#define NAND_HAS_COPYBACK(chip) ((chip->options & NAND_COPYBACK))
+/* Large page NAND with SOFT_ECC should support subpage reads */
+#define NAND_SUBPAGE_READ(chip) ((chip->ecc.mode == NAND_ECC_SOFT) \
+					&& (chip->page_shift > 9))
+
+/* Mask to zero out the chip options, which come from the id table */
+#define NAND_CHIPOPTIONS_MSK	(0x0000ffff & ~NAND_NO_AUTOINCR)
+
+/* Non chip related options */
+/* Use a flash based bad block table. This option is passed to the
+ * default bad block table function. */
+#define NAND_USE_FLASH_BBT	0x00010000
+/* This option skips the bbt scan during initialization. */
+#define NAND_SKIP_BBTSCAN	0x00020000
+/* This option is defined if the board driver allocates its own buffers
+   (e.g. because it needs them DMA-coherent */
+#define NAND_OWN_BUFFERS	0x00040000
+/* Options set by nand scan */
+/* bbt has already been read */
+#define NAND_BBT_SCANNED	0x40000000
+/* Nand scan has allocated controller struct */
+#define NAND_CONTROLLER_ALLOC	0x80000000
+
+/* Cell info constants */
+#define NAND_CI_CHIPNR_MSK	0x03
+#define NAND_CI_CELLTYPE_MSK	0x0C
+
+/*
+ * NAND Flash Manufacturer ID Codes
+ */
+#define NAND_MFR_TOSHIBA	0x98
+#define NAND_MFR_SAMSUNG	0xec
+#define NAND_MFR_FUJITSU	0x04
+#define NAND_MFR_NATIONAL	0x8f
+#define NAND_MFR_RENESAS	0x07
+#define NAND_MFR_STMICRO	0x20
+#define NAND_MFR_HYNIX		0xad
+#define NAND_MFR_MICRON		0x2c
+#define NAND_MFR_AMD		0x01
+
+/*
+* Constants for oob configuration
+*/
+#define NAND_SMALL_BADBLOCK_POS		5
+#define NAND_LARGE_BADBLOCK_POS		0
+
+
+#if defined(CONFIG_S3C2410)
+#define REG_NFCONF      __REGi(ELFIN_NAND_BASE + 0x0)
+#define REG_NFCMD       __REGb(ELFIN_NAND_BASE + 0x4)
+#define REG_NFADDR      __REGb(ELFIN_NAND_BASE + 0x8)
+#define REG_NFDATA      __REGb(ELFIN_NAND_BASE + 0xc)
+#define REG_NFSTAT      __REGb(ELFIN_NAND_BASE + 0x10)
+#define NFSTAT_BUSY 1
+#define nand_select()   (REG_NFCONF &= ~0x800)   /*Clear bit 11*/
+#define nand_deselect() (REG_NFCONF |= 0x800)
+#define nand_clear_RnB()    do {} while (0)  
+#define nand_detect_RnB()    do {} while (0)  
+#define nand_wait_RnB()    do {} while (0)  
+
+#elif defined(CONFIG_S3C2440) || defined(CONFIG_S3C2442)
+
+#define REG_NFCONF      __REGi(ELFIN_NAND_BASE + 0x0)
+#define REG_NFCONT      __REGi(ELFIN_NAND_BASE + 0x4)
+#define REG_NFCMD       __REGb(ELFIN_NAND_BASE + 0x8)
+#define REG_NFADDR      __REGb(ELFIN_NAND_BASE + 0xc)
+#define REG_NFDATA      __REGb(ELFIN_NAND_BASE + 0x10)
+#define REG_NFDATA16    __REGw(ELFIN_NAND_BASE + 0x10)
+#define REG_NFSTAT      __REGb(ELFIN_NAND_BASE + 0x20)
+#define NFSTAT_BUSY 1
+#define nand_select()   (REG_NFCONT &= ~(1 << 1))
+#define nand_deselect() (REG_NFCONT |= (1 << 1))
+#define nand_clear_RnB()    (REG_NFSTAT |= (1 << 2))
+#define nand_detect_RnB()   {while(!(REG_NFSTAT&(1<<2)));}   /*Wait Read & Busy signal goto high(not busy)*/ 
+#define nand_wait_RnB()   {while(!(REG_NFSTAT&(1<<0)));}   /*Wait nand flash not busy, wait bit[0] goes to 1*/ 
+
+#endif
+
+#define SKIP_BAD_BLOCK       1
+#define NOT_SKIP_BAD_BLOCK   0
+
+struct boot_nand_t
+{
+    int page_size; 
+    int spare_size; 
+    int block_size; 
+    int block_num;
+    int bad_block_offset; 
+    int id;
+    //  unsigned long size;
+};
+
+int nand_init(struct boot_nand_t *nand);
+int nand_read_page(struct boot_nand_t *nand, ulong page_num, ulong offset, char *data, ulong size);
+int nand_write_page(struct boot_nand_t *nand, ulong page_num, ulong offset, char *data, ulong size);
+int is_bad_block(struct boot_nand_t *nand, ulong addr);
+int mark_bad_block(struct boot_nand_t *nand, ulong addr);
+int nand_erase_block(struct boot_nand_t *nand, ulong block_num);
+int nand_erase(struct boot_nand_t *nand, ulong start_addr, ulong size, int skip_bad);
+void nand_scrub(struct boot_nand_t *nand);
+int nand_read_spare(struct boot_nand_t *nand, ulong page_addr, int size, char *buf);
+int nand_write_spare(struct boot_nand_t *nand, ulong page_addr, int size, char *buf);
+int nand_read(struct boot_nand_t *nand, ulong start_addr, ulong size, char *buf);
+int nand_write(struct boot_nand_t *nand, ulong start_addr, ulong size, char *buf);
+
+
+
+#endif                          /* __LINUX_MTD_NAND_H */
diff --git a/linux-bsp/asm-study/myboot/rsa.c b/linux-bsp/asm-study/myboot/rsa.c
new file mode 100644
index 0000000..fb5ca06
--- /dev/null
+++ b/linux-bsp/asm-study/myboot/rsa.c
@@ -0,0 +1,602 @@
+/*
+ *  The RSA PK cryptosystem
+ *
+ *  Copyright (C) 2006  Christophe Devine
+ *
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Lesser General Public
+ *  License, version 2.1 as published by the Free Software Foundation.
+ *
+ *  This library is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser General Public
+ *  License along with this library; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+ *  MA  02110-1301  USA
+ */
+/*
+ *  RSA was designed by Ron Rivest, Adi Shamir and Len Adleman.
+ *
+ *  http://theory.lcs.mit.edu/~rivest/rsapaper.pdf
+ *  http://www.cacr.math.uwaterloo.ca/hac/about/chap8.pdf
+ */
+
+#ifndef _CRT_SECURE_NO_DEPRECATE
+#define _CRT_SECURE_NO_DEPRECATE 1
+#endif
+
+#include <common.h>
+#include <rsa.h>
+
+#if !defined(NO_GENPRIME)
+/*
+ * Generate an RSA keypair
+ */
+int rsa_gen_key( rsa_context *ctx, int nbits, int exponent,
+                 int (*rng_f)(void *), void *rng_d )
+{
+    int ret;
+    mpi P1, Q1, H, G;
+
+    if( nbits < 128 || exponent < 3 || rng_f == NULL )
+        return( ERR_RSA_BAD_INPUT_DATA );
+
+    mpi_init( &P1, &Q1, &H, &G, NULL );
+
+    memset( ctx, 0, sizeof( rsa_context ) );
+
+    /*
+     * find primes P and Q with Q < P so that:
+     * GCD( E, (P-1)*(Q-1) ) == 1
+     */
+    CHK( mpi_lset( &ctx->E, exponent ) );
+
+    nbits >>= 1;
+
+    do
+    {
+        CHK( mpi_gen_prime( &ctx->P, nbits, 0, rng_f, rng_d ) );
+        CHK( mpi_gen_prime( &ctx->Q, nbits, 0, rng_f, rng_d ) );
+
+        if( mpi_cmp_mpi( &ctx->P, &ctx->Q ) < 0 )
+            mpi_swap( &ctx->P, &ctx->Q );
+
+        if( mpi_cmp_mpi( &ctx->P, &ctx->Q ) == 0 )
+            continue;
+
+        CHK( mpi_mul_mpi( &ctx->N, &ctx->P, &ctx->Q ) );
+        CHK( mpi_sub_int( &P1, &ctx->P, 1 ) );
+        CHK( mpi_sub_int( &Q1, &ctx->Q, 1 ) );
+        CHK( mpi_mul_mpi( &H, &P1, &Q1 ) );
+        CHK( mpi_gcd( &G, &ctx->E, &H  ) );
+    }
+    while( mpi_cmp_int( &G, 1 ) != 0 );
+
+    /*
+     * D  = E^-1 mod ((P-1)*(Q-1))
+     * DP = D mod (P - 1)
+     * DQ = D mod (Q - 1)
+     * QP = Q^-1 mod P
+     */
+    CHK( mpi_inv_mod( &ctx->D , &ctx->E, &H  ) );
+    CHK( mpi_mod_mpi( &ctx->DP, &ctx->D, &P1 ) );
+    CHK( mpi_mod_mpi( &ctx->DQ, &ctx->D, &Q1 ) );
+    CHK( mpi_inv_mod( &ctx->QP, &ctx->Q, &ctx->P ) );
+
+    ctx->len = ( mpi_size( &ctx->N ) + 7 ) >> 3;
+
+cleanup:
+
+    mpi_free( &P1, &Q1, &H, &G, NULL );
+
+    if( ret != 0 )
+    {
+        rsa_free( ctx );
+        return( ERR_RSA_KEY_GEN_FAILED | ret );
+    }
+
+    return( 0 );   
+}
+#endif
+
+/*
+ * Perform an RSA public key operation
+ */
+int rsa_public( rsa_context   *ctx,
+                unsigned char *input,  int ilen,
+                unsigned char *output, int *olen )
+{
+    int ret;
+    mpi T;
+
+   // if( ilen != ctx->len || olen != ctx->len )
+   //    return( ERR_RSA_BAD_INPUT_DATA );
+
+
+    mpi_init( &T, NULL );
+
+    CHK( mpi_import( &T, input, ilen ) );
+
+    if( mpi_cmp_mpi( &T, &ctx->N ) >= 0 )
+    {
+        mpi_free( &T, NULL );
+        return( ERR_RSA_BAD_INPUT_DATA );
+    }
+
+    CHK( mpi_exp_mod( &T, &T, &ctx->E, &ctx->N, &ctx->RN ) );
+    CHK( mpi_export( &T, output, olen ) );
+
+cleanup:
+
+    mpi_free( &T, NULL );
+
+    if( ret != 0 )
+        return( ERR_RSA_PUBLIC_FAILED | ret );
+
+    return( 0 );
+}
+
+/*
+ * Perform an RSA private key operation
+ */
+int rsa_private( rsa_context   *ctx,
+                 unsigned char *input,  int ilen,
+                 unsigned char *output, int *olen )
+{
+    int ret;
+    mpi T, T1, T2;
+
+   //if( ilen != ctx->len || olen != ctx->len )
+   //    return( ERR_RSA_BAD_INPUT_DATA );
+
+    mpi_init( &T, &T1, &T2, NULL );
+
+    CHK( mpi_import( &T, input, ilen ) );
+
+    if( mpi_cmp_mpi( &T, &ctx->N ) >= 0 )
+    {
+        mpi_free( &T, NULL );
+        return( ERR_RSA_BAD_INPUT_DATA );
+    }
+
+#if 0
+    CHK( mpi_exp_mod( &T, &T, &ctx->D, &ctx->N, &ctx->RN ) );
+#else
+    /*
+     * faster decryption using the CRT
+     *
+     * T1 = input ^ dP mod P
+     * T2 = input ^ dQ mod Q
+     */
+    CHK( mpi_exp_mod( &T1, &T, &ctx->DP, &ctx->P, &ctx->RP ) );
+    CHK( mpi_exp_mod( &T2, &T, &ctx->DQ, &ctx->Q, &ctx->RQ ) );
+
+    /*
+     * T = (T1 - T2) * (Q^-1 mod P) mod P
+     */
+    CHK( mpi_sub_mpi( &T, &T1, &T2 ) );
+    CHK( mpi_mul_mpi( &T1, &T, &ctx->QP ) );
+    CHK( mpi_mod_mpi( &T, &T1, &ctx->P ) );
+
+    /*
+     * output = T2 + T * Q
+     */
+    CHK( mpi_mul_mpi( &T1, &T, &ctx->Q ) );
+    CHK( mpi_add_mpi( &T, &T2, &T1 ) );
+#endif
+
+    CHK( mpi_export( &T, output, olen ) );
+
+cleanup:
+
+    mpi_free( &T, &T1, &T2, NULL );
+
+    if( ret != 0 )
+        return( ERR_RSA_PRIVATE_FAILED | ret );
+
+    return( 0 );
+}
+
+/*
+ * Check if the public key is valid
+ */
+int rsa_check_pubkey( rsa_context *ctx )
+{
+    if( ( ctx->N.p[0] & 1 ) == 0 || 
+        ( ctx->E.p[0] & 1 ) == 0 )
+        return( ERR_RSA_KEY_CHK_FAILED );
+
+    if( mpi_size( &ctx->N ) < 128 ||
+        mpi_size( &ctx->N ) > 4096 )
+        return( ERR_RSA_KEY_CHK_FAILED );
+
+    if( mpi_size( &ctx->E ) < 2 ||
+        mpi_size( &ctx->E ) > 64 )
+        return( ERR_RSA_KEY_CHK_FAILED );
+
+    return( 0 );
+}
+
+/*
+ * Check if the private key is valid
+ */
+int rsa_check_privkey( rsa_context *ctx )
+{
+    int ret = 0;
+    mpi TN, P1, Q1, H, G;
+
+    mpi_init( &TN, &P1, &Q1, &H, &G, NULL );
+
+    CHK( mpi_mul_mpi( &TN, &ctx->P, &ctx->Q ) );
+    CHK( mpi_sub_int( &P1, &ctx->P, 1 ) );
+    CHK( mpi_sub_int( &Q1, &ctx->Q, 1 ) );
+    CHK( mpi_mul_mpi( &H, &P1, &Q1 ) );
+    CHK( mpi_gcd( &G, &ctx->E, &H  ) );
+
+    if( mpi_cmp_mpi( &TN, &ctx->N ) == 0 &&
+        mpi_cmp_int( &G, 1 ) == 0 )
+    {
+        mpi_free( &TN, &P1, &Q1, &H, &G, NULL );
+        return( 0 );
+    }
+
+cleanup:
+
+    mpi_free( &TN, &P1, &Q1, &H, &G, NULL );
+    return( ERR_RSA_KEY_CHK_FAILED | ret );
+}
+
+/*
+ * Add the PKCS#1 v1.5 padding and do a public RSA
+ */
+int rsa_pkcs1_encrypt( rsa_context   *ctx,
+                       unsigned char *input,  int ilen,
+                       unsigned char *output, int *olen )
+{
+    int nb_pad;
+    unsigned char *p = output;
+
+    if( *olen != ctx->len || *olen < ilen + 11 )
+    {
+        return( ERR_RSA_BAD_INPUT_DATA );
+    }
+
+    nb_pad = *olen - 3 - ilen;
+
+    *p++ = 0;
+    *p++ = RSA_CRYPT;
+
+    while( nb_pad-- > 0 )
+    {
+        do { *p = rand(); } while( *p == 0 );
+        p++;
+    }
+
+    *p++ = 0;
+    memcpy( p, input, ilen );
+
+    return( rsa_public( ctx, output, *olen, output, olen ) );
+}
+
+/*
+ * Do a private RSA, removes the PKCS#1 v1.5 padding
+ */
+int rsa_pkcs1_decrypt( rsa_context   *ctx,
+                       unsigned char *input,  int  ilen,
+                       unsigned char *output, int *olen )
+{
+    int ret;
+    unsigned char *p, buf[512];
+
+    if( ilen != ctx->len || ilen < 16 || ilen > 512 )
+        return( ERR_RSA_BAD_INPUT_DATA );
+
+    if( ( ret = rsa_private( ctx, input, ilen, buf, &ilen ) ) != 0 )
+        return( ret );
+
+    p = buf;
+
+    if( *p++ != 0 || *p++ != RSA_CRYPT )
+        return( ERR_RSA_INVALID_PADDING );
+
+    while( *p != 0 )
+    {
+        if( p >= buf + ilen - 1 )
+            return( ERR_RSA_INVALID_PADDING );
+        p++;
+    }
+    p++;
+
+    if( *olen < ilen - (int)(p - buf) )
+        return( ERR_RSA_INVALID_PADDING );
+
+    *olen = ilen - (int)(p - buf);
+    memcpy( output, p, *olen );
+
+    return( 0 );
+}
+
+/*
+ * Perform a private RSA to sign a message digest
+ */
+int rsa_pkcs1_sign( rsa_context   *ctx,  int alg_id,
+                    unsigned char *hash, int hashlen,
+                    unsigned char *sig,  int siglen )
+{
+    int nb_pad;
+    unsigned char *p = sig;
+
+    if( siglen != ctx->len || siglen < 16 )
+        return( ERR_RSA_BAD_INPUT_DATA );
+
+    switch( alg_id )
+    {
+        case RSA_RAW:
+            nb_pad = siglen - 3 - hashlen;
+            break;
+
+        case RSA_MD2:
+        case RSA_MD4:
+        case RSA_MD5:
+            nb_pad = siglen - 3 - 34;
+            break;
+
+        case RSA_SHA1:
+            nb_pad = siglen - 3 - 35;
+            break;
+
+        default:
+            return( ERR_RSA_BAD_INPUT_DATA );
+    }
+
+    if( nb_pad < 8 )
+        return( ERR_RSA_BAD_INPUT_DATA );
+
+    *p++ = 0;
+    *p++ = RSA_SIGN;
+
+    memset( p, 0xFF, nb_pad );
+    p += nb_pad;
+    *p++ = 0;
+
+    switch( alg_id )
+    {
+        case RSA_RAW:
+            memcpy( p, hash, hashlen );
+            break;
+
+        case RSA_MD2:
+            memcpy( p, ASN1_HASH_MDX, 18 );
+            memcpy( p + 18, hash, 16 );
+            p[13] = 2; break;
+
+        case RSA_MD4:
+            memcpy( p, ASN1_HASH_MDX, 18 );
+            memcpy( p + 18, hash, 16 );
+            p[13] = 4; break;
+
+        case RSA_MD5:
+            memcpy( p, ASN1_HASH_MDX, 18 );
+            memcpy( p + 18, hash, 16 );
+            p[13] = 5; break;
+
+        case RSA_SHA1:
+            memcpy( p, ASN1_HASH_SHA1, 15 );
+            memcpy( p + 15, hash, 20 );
+            break;
+
+        default:
+            return( ERR_RSA_BAD_INPUT_DATA );
+    }
+
+    return( rsa_private( ctx, sig, siglen, sig, &siglen ) );
+}
+
+/*
+ * Perform a public RSA and check the message digest
+ */
+int rsa_pkcs1_verify( rsa_context   *ctx,  int alg_id,
+                      unsigned char *hash, int hashlen,
+                      unsigned char *sig,  int siglen )
+{
+    int ret, len;
+    unsigned char *p, c, buf[512];
+
+    if( siglen != ctx->len || siglen < 16 || siglen > 512 )
+        return( ERR_RSA_BAD_INPUT_DATA );
+
+    if( ( ret = rsa_public( ctx, sig, siglen, buf, &siglen ) ) != 0 )
+        return( ret );
+
+    p = buf;
+
+    if( *p++ != 0 || *p++ != RSA_SIGN )
+        return( ERR_RSA_INVALID_PADDING );
+
+    while( *p != 0 )
+    {
+        if( p >= buf + siglen - 1 || *p != 0xFF )
+            return( ERR_RSA_INVALID_PADDING );
+        p++;
+    }
+    p++;
+
+    len = siglen - (int)( p - buf );
+
+    if( len == 34 )
+    {
+        c = p[13];
+        p[13] = 0;
+
+        if( memcmp( p, ASN1_HASH_MDX, 18 ) != 0 )
+            return( ERR_RSA_VERIFY_FAILED );
+
+        if( ( c == 2 && alg_id == RSA_MD2 ) ||
+            ( c == 4 && alg_id == RSA_MD4 ) ||
+            ( c == 5 && alg_id == RSA_MD5 ) )
+        {
+            if( memcmp( p + 18, hash, 16 ) == 0 ) 
+                return( 0 );
+            else
+                return( ERR_RSA_VERIFY_FAILED );
+        }
+    }
+
+    if( len == 35 && alg_id == RSA_SHA1 )
+    {
+        if( memcmp( p, ASN1_HASH_SHA1, 15 ) == 0 &&
+            memcmp( p + 15, hash, 20 ) == 0 )
+            return( 0 );
+        else
+            return( ERR_RSA_VERIFY_FAILED );
+    }
+
+    if( len == hashlen && alg_id == RSA_RAW )
+    {
+        if( memcmp( p, hash, hashlen ) == 0 )
+            return( 0 );
+        else
+            return( ERR_RSA_VERIFY_FAILED );
+    }
+
+    return( ERR_RSA_INVALID_PADDING );
+}
+
+/*
+ * Free the components of an RSA key
+ */
+void rsa_free( rsa_context *ctx )
+{
+    mpi_free( &ctx->N,  &ctx->E,  &ctx->D,
+              &ctx->P,  &ctx->Q,  &ctx->DP,
+              &ctx->DQ, &ctx->QP, &ctx->RN,
+              &ctx->RP, &ctx->RQ, NULL );
+}
+
+//#include "md5.h"
+
+#define PTLEN   24
+#define CTLEN  128
+
+/*
+ * Checkup routine
+ */
+int main ( void )
+{
+    int len;
+    rsa_context rsa;
+    unsigned char md5sum[16];
+    unsigned char rsa_plaintext[PTLEN];
+    unsigned char rsa_decrypted[PTLEN];
+    unsigned char rsa_ciphertext[CTLEN];
+
+    memset( &rsa, 0, sizeof( rsa ) );
+
+    rsa.len = 128;
+
+    mpi_read( &rsa.N , "9292758453063D803DD603D5E777D788" \
+                       "8ED1D5BF35786190FA2F23EBC0848AEA" \
+                       "DDA92CA6C3D80B32C4D109BE0F36D6AE" \
+                       "7130B9CED7ACDF54CFC7555AC14EEBAB" \
+                       "93A89813FBF3C4F8066D2D800F7C38A8" \
+                       "1AE31942917403FF4946B0A83D3D3E05" \
+                       "EE57C6F5F5606FB5D4BC6CD34EE0801A" \
+                       "5E94BB77B07507233A0BC7BAC8F90F79", 16 );
+
+    mpi_read( &rsa.E , "10001", 16 );
+    mpi_read( &rsa.D , "24BF6185468786FDD303083D25E64EFC" \
+                       "66CA472BC44D253102F8B4A9D3BFA750" \
+                       "91386C0077937FE33FA3252D28855837" \
+                       "AE1B484A8A9A45F7EE8C0C634F99E8CD" \
+                       "DF79C5CE07EE72C7F123142198164234" \
+                       "CABB724CF78B8173B9F880FC86322407" \
+                       "AF1FEDFDDE2BEB674CA15F3E81A1521E" \
+                       "071513A1E85B5DFA031F21ECAE91A34D", 16 );
+
+    mpi_read( &rsa.P , "C36D0EB7FCD285223CFB5AABA5BDA3D8" \
+                       "2C01CAD19EA484A87EA4377637E75500" \
+                       "FCB2005C5C7DD6EC4AC023CDA285D796" \
+                       "C3D9E75E1EFC42488BB4F1D13AC30A57", 16 );
+    mpi_read( &rsa.Q , "C000DF51A7C77AE8D7C7370C1FF55B69" \
+                       "E211C2B9E5DB1ED0BF61D0D9899620F4" \
+                       "910E4168387E3C30AA1E00C339A79508" \
+                       "8452DD96A9A5EA5D9DCA68DA636032AF", 16 );
+
+    mpi_read( &rsa.DP, "C1ACF567564274FB07A0BBAD5D26E298" \
+                       "3C94D22288ACD763FD8E5600ED4A702D" \
+                       "F84198A5F06C2E72236AE490C93F07F8" \
+                       "3CC559CD27BC2D1CA488811730BB5725", 16 );
+    mpi_read( &rsa.DQ, "4959CBF6F8FEF750AEE6977C155579C7" \
+                       "D8AAEA56749EA28623272E4F7D0592AF" \
+                       "7C1F1313CAC9471B5C523BFE592F517B" \
+                       "407A1BD76C164B93DA2D32A383E58357", 16 );
+    mpi_read( &rsa.QP, "9AE7FBC99546432DF71896FC239EADAE" \
+                       "F38D18D2B2F0E2DD275AA977E2BF4411" \
+                       "F5A3B2A5D33605AEBBCCBA7FEB9F2D2F" \
+                       "A74206CEC169D74BF5A8C50D6F48EA08", 16 );
+
+    printf( "  RSA key validation: " );
+
+    if( rsa_check_pubkey(  &rsa ) != 0 ||
+        rsa_check_privkey( &rsa ) != 0 )
+    {
+        printf( "failed\n" );
+        return( 1 );
+    }
+
+    printf( "passed\n  PKCS#1 encryption : " );
+
+    memcpy( rsa_plaintext,
+        "\xAA\xBB\xCC\x03\x02\x01\x00\xFF\xFF\xFF\xFF\xFF" \
+        "\x11\x22\x33\x0A\x0B\x0C\xCC\xDD\xDD\xDD\xDD\xDD", PTLEN );
+
+    len = CTLEN;
+    if( rsa_pkcs1_encrypt( &rsa, rsa_plaintext,  PTLEN,
+                                 rsa_ciphertext, &len ) != 0 )
+    {
+        printf( "failed\n" );
+        return( 1 );
+    }
+
+    printf( "passed\n  PKCS#1 decryption : " );
+
+    len = sizeof( rsa_decrypted );
+
+    if( rsa_pkcs1_decrypt( &rsa, rsa_ciphertext, CTLEN,
+                                 rsa_decrypted,  &len ) != 0 ||
+        memcmp( rsa_decrypted, rsa_plaintext, len ) != 0 )
+    {
+        printf( "failed\n" );
+        return( 1 );
+    }
+
+    printf( "passed\n" );
+
+#if 0
+    md5_csum( rsa_plaintext, PTLEN, md5sum );
+
+    if( rsa_pkcs1_sign( &rsa, RSA_MD5, md5sum, 16,
+                        rsa_ciphertext, CTLEN ) != 0 )
+    {
+        printf( "failed\n" );
+        return( 1 );
+    }
+
+    printf( "passed\n  PKCS#1 sig. verify: " );
+
+    if( rsa_pkcs1_verify( &rsa, RSA_MD5, md5sum, 16,
+                          rsa_ciphertext, CTLEN ) != 0 )
+    {
+        printf( "failed\n" );
+        return( 1 );
+    }
+
+    printf( "passed\n\n" );
+#endif
+
+    rsa_free( &rsa );
+    return( 0 );
+}
diff --git a/linux-bsp/asm-study/myboot/serial.c b/linux-bsp/asm-study/myboot/serial.c
new file mode 100644
index 0000000..5e7063a
--- /dev/null
+++ b/linux-bsp/asm-study/myboot/serial.c
@@ -0,0 +1,74 @@
+/********************************************************************************************
+ *        File:  serial.c
+ *     Version:  1.0.0
+ *   Copyright:  2011 (c) Guo Wenxue <guowenxue@gmail.com>
+ * Description:  The UART on board drivers/functions.
+ *   ChangeLog:  1, Release initial version on "Tue Jul 12 16:43:18 CST 2011"
+ *
+ *******************************************************************************************/
+
+#include <common.h>
+#define GPHCON   (*(unsigned long volatile *)0x56000070)
+
+void serial_init(void)
+{
+    S3C24X0_UART *const uart = (S3C24X0_UART *) ELFIN_UART_BASE;
+
+    /*Enable UART0,UART1,UART2 */
+    GPHCON = 0x0000aaaa;
+
+    /*Set Parity, Stopbit etc. */
+    uart->ULCON &= 0XFFFFFF00;
+    uart->ULCON |= 0X03;
+
+    /*Disable modem */
+    uart->UMCON = 0x0;
+
+    /*Set UART FIFO control register */
+    uart->UFCON = 0x00;
+    uart->UCON = 0x805;         /*Enable FIFO */
+
+    /* 
+     * UBRDIV = (UART Clock)/(baudrate*16) -1 
+     *        = (50 000 000)/(115200*16) -1 
+     *        = 26 
+     *        = 0x1A
+     */
+    uart->UBRDIV = 0x1A;
+}
+
+void serial_send_byte(char c)
+{
+    S3C24X0_UART *const uart = (S3C24X0_UART *) ELFIN_UART_BASE;
+    /* wait for room in the tx FIFO */
+    while (!(uart->UTRSTAT & 0x2)) ;
+
+    uart->UTXH = c;
+
+    if (c == '\n')              /* If \n, also do \r */
+        serial_send_byte('\r');
+}
+
+int serial_is_recv_enable(void)
+{
+    S3C24X0_UART *const uart = (S3C24X0_UART *) ELFIN_UART_BASE;
+    return uart->UTRSTAT & 0x1;
+}
+
+int serial_recv_byte(void)
+{
+    S3C24X0_UART *const uart = (S3C24X0_UART *) ELFIN_UART_BASE;
+
+    /* wait for character to arrive */
+    while (!(uart->UTRSTAT & 0x1)) ;
+
+    return uart->URXH & 0xff;
+}
+
+void serial_puts(const char *s)
+{
+    while (*s)
+    {
+        serial_send_byte(*s++);
+    }
+}
diff --git a/linux-bsp/asm-study/myboot/start.S b/linux-bsp/asm-study/myboot/start.S
new file mode 100644
index 0000000..05698d7
--- /dev/null
+++ b/linux-bsp/asm-study/myboot/start.S
@@ -0,0 +1,348 @@
+
+/********************************************************************************************
+ *        File:  start.S - Startup Code for ARM920 CPU-core
+ *     Version:  1.0.0
+ *   Copyright:  2011 (c) Guo Wenxue <guowenxue@gmail.com>
+ * Description:  When system power up, the CPU will comes here to excute the first code here.
+ *   ChangeLog:  1, Release initial version on "Tue Jul 12 16:43:18 CST 2011"
+ *
+ *******************************************************************************************/
+
+
+/*
+ *************************************************************************
+ *
+ * Jump vector table as in table 3.1 in [1]
+ *
+ *************************************************************************
+ */
+
+#include <config.h>
+
+.globl _start
+_start:	b	start_code
+	ldr	pc, _undefined_instruction
+	ldr	pc, _software_interrupt
+	ldr	pc, _prefetch_abort
+	ldr	pc, _data_abort
+	ldr	pc, _not_used
+	ldr	pc, _irq
+	ldr	pc, _fiq
+
+_undefined_instruction:	.word undefined_instruction
+_software_interrupt:	.word software_interrupt
+_prefetch_abort:	.word prefetch_abort
+_data_abort:		.word data_abort
+_not_used:		.word not_used
+_irq:			.word irq
+_fiq:			.word fiq
+
+	.balignl 16,0xdeadbeef
+
+
+/*
+ *************************************************************************
+ *
+ * Startup Code (called from the ARM reset exception vector)
+ *
+ * do important init only if we don't start from memory!
+ * relocate armboot to ram
+ * setup stack
+ * jump to second stage
+ *
+ *************************************************************************
+ */
+
+_TEXT_BASE:
+	.word	TEXT_BASE
+
+.globl _armboot_start
+_armboot_start:
+	.word _start
+
+/*
+ * These are defined in the board-specific linker script.
+ */
+.globl _bss_start
+_bss_start:
+	.word __bss_start
+
+.globl _bss_end
+_bss_end:
+	.word _end
+
+/*
+ * the actual start code
+ */
+
+start_code:
+	/*
+	 * set the cpu to SVC32 mode
+	 */
+	mrs	r0, cpsr
+	bic	r0, r0, #0x1f
+	orr	r0, r0, #0xd3
+	msr	cpsr, r0
+
+	/* Disable watchdog */
+    ldr r0, =ELFIN_WATCHDOG_BASE
+    mov r1, #0
+    str r1, [r0]
+
+	/* Disable Interrupt */
+    ldr r0, =ELFIN_INTERRUPT_BASE
+    mov r1, #0xffffffff
+    str r1, [r0, #INTMSK_OFFSET]
+    ldr r1, =0x000007ff
+    str r1, [r0, #INTSUBMSK_OFFSET]
+
+	/* flush v4 I/D caches */
+	mov	r0, #0
+	mcr	p15, 0, r0, c7, c7, 0	/* flush v3/v4 cache */
+	mcr	p15, 0, r0, c8, c7, 0	/* flush v4 TLB */
+
+	/* disable MMU stuff and caches */
+	mrc	p15, 0, r0, c1, c0, 0
+	bic	r0, r0, #0x00002300	@ clear bits 13, 9:8 (--V- --RS)
+	bic	r0, r0, #0x00000087	@ clear bits 7, 2:0 (B--- -CAM)
+	orr	r0, r0, #0x00000002	@ set bit 2 (A) Align
+	orr	r0, r0, #0x00001000	@ set bit 12 (I) I-Cache
+	mcr	p15, 0, r0, c1, c0, 0
+
+
+ /*******************************************************************************************
+  * Init system clock and power, FCLK:HCLK:PCLK = 1:4:8 
+  * Reference to S3C2440 datasheet: Chap 7 Clock&Power Management
+  *
+  * Initialize System Clock FCLK=400MHz HCLK=100MHz PCLK=50MHz
+  * FCLK is used by ARM920T
+  * HCLK is used for AHB bus, which is used by the ARM920T, the memory controller,
+  *      the interrupt controller, the LCD controller, the DMA and USB host block.
+  * PCLK is is used for APB bus,which is used by the peripherals such as WDT,IIS,I2C,
+  *      PWM timer,MMC interface,ADC,UART,GPIO,RTC and SPI.
+  ******************************************************************************************/
+
+    /*Set LOCKTIME as default value 0x00ffffff*/
+    ldr r0, =ELFIN_CLOCK_POWER_BASE
+    ldr r1, =0x00ffffff
+    str r1, [r0, #LOCKTIME_OFFSET] 
+
+ /*******************************************************************************************
+  * Reference to S3C2440 datasheet: Chap 7-8 ~ Page 242
+  *
+  * Set the selection of Dividing Ratio between FCLK,HCLK and PCLK as FCLK:HCLK:PCLK = 1:4:8.
+  * This ratio is determined by HDIVN(here is 2) and PDIVN(here is 1) control register.
+  * Refer to the s3c2440 datasheet
+  *******************************************************************************************/
+    ldr r0, =ELFIN_CLOCK_POWER_BASE
+    mov r1, #5
+    str r1, [r0, #CLKDIVN_OFFSET]  /*Set Clock Divider*/
+
+    mrc p15, 0, r1, c1, c0, 0 
+    orr r1, r1, #0xc0000000
+    mcr p15, 0, r1, c1, c0, 0 
+
+ /***************************************************************************************
+  *  Reference to S3C2440 datasheet: Chap 7-20 ~ Page 254
+  *
+  *  Set MPLLCON(0x4C000004) register as:
+  *    [19:12]:  MDIV(Main Divider control)=0x7F (value set in MDIV_405)
+  *      [9:4]:  PDIV(Pre-devider control)=0x02  (value set in PSDIV_405)
+  *      [1:0]:  SDIV(Post divider control)=0x01 (value set in PSDIV_405)
+  *
+  *  MPLL(FCLK) = (2 * m * Fin)/(p * 2^s)
+  *  m=(MDIV+8), p=(PDIV+2), s=SDIV
+  *
+  *  So FCLK=((2*(127+8)*Fin)) / ((2+2)*2^1)
+  *         = (2*135*12MHz)/8
+  *         = 405MHz
+  *  For FCLK:HCLK:PCLK=1:4:8, so HCLK=100MHz, PCLK=50MHz
+  ***************************************************************************************/
+    mov r1, #ELFIN_CLOCK_POWER_BASE
+    mov r2, #MDIV_405
+    add r2, r2, #PSDIV_405
+    str r2, [r1, #MPLLCON_OFFSET]
+
+    /* Go to mem_init.S to Init memory controller register */
+	bl	mem_init
+
+	/* Set up the stack	*/
+stack_setup:
+	ldr	r0, =STACK_BASE		/* upper 128 KiB: relocated uboot   */
+	sub	r0, r0, #CONFIG_SYS_MALLOC_LEN	/* malloc area              */
+	sub	r0, r0, #CONFIG_SYS_GBL_DATA_SIZE /* bdinfo                 */
+	sub	sp, r0, #12		/* leave 3 words for abort-stack    */
+	bic	sp, sp, #7		/* 8-byte alignment for ABI compliance */
+
+clear_bss:
+	ldr	r0, _bss_start		/* find start of bss segment        */
+	ldr	r1, _bss_end		/* stop here                        */
+	mov	r2, #0x00000000		/* clear                            */
+
+clbss_l:str	r2, [r0]		/* clear loop...                    */
+	add	r0, r0, #4
+	cmp	r0, r1
+	ble	clbss_l
+
+#if 0  /*Don't wanna init BEEP & LED here*/
+    bl  init_led_beep
+
+    /*
+     * R0,R1,R2 are the 1st,2nd, 3rd argument passed to C function
+     * If need pass more than 3 arguments, then we need use stack.
+     */
+    mov r0,#LED1    
+    bl  turn_led_on
+#endif
+
+    bl  bootstrap_main
+
+/*
+ *************************************************************************
+ *
+ * Interrupt handling
+ *
+ *************************************************************************
+ */
+
+@
+@ IRQ stack frame.
+@
+#define S_FRAME_SIZE	72
+
+#define S_OLD_R0	68
+#define S_PSR		64
+#define S_PC		60
+#define S_LR		56
+#define S_SP		52
+
+#define S_IP		48
+#define S_FP		44
+#define S_R10		40
+#define S_R9		36
+#define S_R8		32
+#define S_R7		28
+#define S_R6		24
+#define S_R5		20
+#define S_R4		16
+#define S_R3		12
+#define S_R2		8
+#define S_R1		4
+#define S_R0		0
+
+#define MODE_SVC	0x13
+#define I_BIT		0x80
+
+/*
+ * use bad_save_user_regs for abort/prefetch/undef/swi ...
+ * use irq_save_user_regs / irq_restore_user_regs for IRQ/FIQ handling
+ */
+
+	.macro	bad_save_user_regs
+	sub	sp, sp, #S_FRAME_SIZE
+	stmia	sp, {r0 - r12}			@ Calling r0-r12
+	ldr	r2, _armboot_start
+	sub	r2, r2, #(CONFIG_STACKSIZE)
+	sub	r2, r2, #(CONFIG_SYS_MALLOC_LEN)
+	/* set base 2 words into abort stack */
+	sub	r2, r2, #(CONFIG_SYS_GBL_DATA_SIZE+8)
+	ldmia	r2, {r2 - r3}			@ get pc, cpsr
+	add	r0, sp, #S_FRAME_SIZE		@ restore sp_SVC
+
+	add	r5, sp, #S_SP
+	mov	r1, lr
+	stmia	r5, {r0 - r3}			@ save sp_SVC, lr_SVC, pc, cpsr
+	mov	r0, sp
+	.endm
+
+	.macro	irq_save_user_regs
+	sub	sp, sp, #S_FRAME_SIZE
+	stmia	sp, {r0 - r12}			@ Calling r0-r12
+	add	r7, sp, #S_PC
+	stmdb	r7, {sp, lr}^			@ Calling SP, LR
+	str	lr, [r7, #0]			@ Save calling PC
+	mrs	r6, spsr
+	str	r6, [r7, #4]			@ Save CPSR
+	str	r0, [r7, #8]			@ Save OLD_R0
+	mov	r0, sp
+	.endm
+
+	.macro	irq_restore_user_regs
+	ldmia	sp, {r0 - lr}^			@ Calling r0 - lr
+	mov	r0, r0
+	ldr	lr, [sp, #S_PC]			@ Get PC
+	add	sp, sp, #S_FRAME_SIZE
+	/* return & move spsr_svc into cpsr */
+	subs	pc, lr, #4
+	.endm
+
+	.macro get_bad_stack
+	ldr	r13, _armboot_start		@ setup our mode stack
+	sub	r13, r13, #(CONFIG_STACKSIZE)
+	sub	r13, r13, #(CONFIG_SYS_MALLOC_LEN)
+	/* reserve a couple spots in abort stack */
+	sub	r13, r13, #(CONFIG_SYS_GBL_DATA_SIZE+8)
+
+	str	lr, [r13]			@ save caller lr / spsr
+	mrs	lr, spsr
+	str	lr, [r13, #4]
+
+	mov	r13, #MODE_SVC			@ prepare SVC-Mode
+	@ msr	spsr_c, r13
+	msr	spsr, r13
+	mov	lr, pc
+	movs	pc, lr
+	.endm
+
+	.macro get_irq_stack			@ setup IRQ stack
+	ldr	sp, IRQ_STACK_START
+	.endm
+
+	.macro get_fiq_stack			@ setup FIQ stack
+	ldr	sp, FIQ_STACK_START
+	.endm
+
+/*
+ * exception handlers
+ */
+	.align  5
+undefined_instruction:
+	get_bad_stack
+	bad_save_user_regs
+	bl	do_undefined_instruction
+
+	.align	5
+software_interrupt:
+	get_bad_stack
+	bad_save_user_regs
+	bl	do_software_interrupt
+
+	.align	5
+prefetch_abort:
+	get_bad_stack
+	bad_save_user_regs
+	bl	do_prefetch_abort
+
+	.align	5
+data_abort:
+	get_bad_stack
+	bad_save_user_regs
+	bl	do_data_abort
+
+	.align	5
+not_used:
+	get_bad_stack
+	bad_save_user_regs
+	bl	do_not_used
+
+	.align	5
+irq:
+	get_bad_stack
+	bad_save_user_regs
+	bl	do_irq
+
+	.align	5
+fiq:
+	get_bad_stack
+	bad_save_user_regs
+	bl	do_fiq
diff --git a/linux-bsp/asm-study/myboot/xmodem.c b/linux-bsp/asm-study/myboot/xmodem.c
new file mode 100644
index 0000000..36345b0
--- /dev/null
+++ b/linux-bsp/asm-study/myboot/xmodem.c
@@ -0,0 +1,121 @@
+/********************************************************************************************
+ *        File:  xmodem.c
+ *     Version:  1.0.0
+ *   Copyright:  2011 (c) Guo Wenxue <guowenxue@gmail.com>
+ * Description:  Xmodem protocal used to download the second stage bootloader(launcher)
+ *   ChangeLog:  1, Release initial version on "Tue Jul 12 16:43:18 CST 2011"
+ *
+ *******************************************************************************************/
+
+#include <common.h>
+
+#define XMODEM_SOH 0x01         /*Start Of Header, standard Xmodem */
+#define XMODEM_STX 0x02         /*1K-Modem start Xmodem */
+#define XMODEM_EOT 0x04         /*End Of Transmission */
+#define XMODEM_ACK 0x06
+#define XMODEM_NAK 0x15
+#define XMODEM_CAN 0x18         /*Stop transmission */
+#define XMODEM_EOF 0x1a         /*CTRL+Z EOF */
+
+#define XMODEM_BLOCK_SIZE 128
+
+static int xmodem_wait(void)
+{
+    long cnt = 0;
+
+    while (!serial_is_recv_enable())
+    {
+        if (++cnt >= 2000000)
+        {
+            cnt = 0;
+            serial_send_byte(XMODEM_NAK);
+        }
+    }
+    return 0;
+}
+
+static int xmodem_read_block(unsigned char block_number, char *buf)
+{
+    unsigned char c, block_num, check_sum;
+    int i;
+
+    block_num = serial_recv_byte();
+    if (block_num != block_number)
+        return -1;
+
+    block_num ^= serial_recv_byte();
+    if (block_num != 0xff)
+        return -1;
+
+    check_sum = 0;
+    for (i = 0; i < XMODEM_BLOCK_SIZE; i++)
+    {
+        c = serial_recv_byte();
+        *(buf++) = c;
+        check_sum += c;
+    }
+
+    check_sum ^= serial_recv_byte();
+    if (check_sum)
+        return -1;
+
+    return i;
+}
+
+long xmodem_recv(char *buf)
+{
+    int r, receiving = 0;
+    long size = 0;
+    unsigned char c, block_number = 1;
+
+    while (1)
+    {
+        if (!receiving)
+            xmodem_wait();
+
+        c = serial_recv_byte();
+
+        switch (c)
+        {
+          case XMODEM_EOT:
+              serial_send_byte(XMODEM_ACK);
+
+              /*Remove the CMPEOF */
+              long cnt = 0;
+              if ((buf[-1] == XMODEM_EOF) && (buf[-2] == XMODEM_EOF) && (buf[-3] == XMODEM_EOF))
+              {
+                  while (size && buf[-cnt - 1] == XMODEM_EOF)
+                      cnt++;
+              }
+
+              size -= cnt;
+              goto RECV_OK;
+
+          case XMODEM_CAN:
+              return -1;
+
+          case XMODEM_SOH:
+              receiving++;
+              r = xmodem_read_block(block_number, buf);
+              if (r < 0)
+              {
+                  serial_send_byte(XMODEM_NAK);
+              }
+              else
+              {
+                  block_number++;
+                  size += r;
+                  buf += r;
+                  serial_send_byte(XMODEM_ACK);
+              }
+              break;
+
+          default:
+              if (receiving)
+                  return -1;
+        }
+    }
+
+  RECV_OK:
+    return size;
+}
diff --git a/linux-bsp/asm-study/yaffs2/bootstrap.c b/linux-bsp/asm-study/yaffs2/bootstrap.c
new file mode 100644
index 0000000..d3077fb
--- /dev/null
+++ b/linux-bsp/asm-study/yaffs2/bootstrap.c
@@ -0,0 +1,202 @@
+/********************************************************************************************
+ *        File:  bootstrap.c
+ *     Version:  1.0.0
+ *   Copyright:  2011 (c) Guo Wenxue <guowenxue@gmail.com>
+ * Description:  This C code is the first stage bootloader(named bootstrap) 
+                 main code, test on FL2440 board.
+ *   ChangeLog:  1, Release initial version on "Tue Jul 12 16:43:18 CST 2011"
+ *
+ *******************************************************************************************/
+
+#include <stdio.h>
+#include <string.h>
+#include <malloc.h>
+#include "yaffsfs.h"
+#include "s3c_board.h"
+
+#define MALLOC_SIZE             20
+
+int mkdir(const char *mp, const char *name)
+{
+    char full_name[100]; 
+    sprintf(full_name, "%s/%s", mp, name); 
+    printf("Create directory [%s]\n", full_name);
+    return yaffs_mkdir(full_name, S_IREAD| S_IWRITE);
+}
+
+int mkfile(const char *mp, const char *name)
+{
+    char full_name[100];
+    char buf[100];
+    int h; 
+    
+    sprintf(full_name, "%s/%s", mp, name); 
+
+    h = yaffs_open(full_name, O_RDWR | O_CREAT | O_TRUNC, S_IREAD| S_IWRITE); 
+    yaffs_write(h, name, strlen(name)); 
+    yaffs_lseek(h, 0, SEEK_SET);
+    memset(buf, 0, sizeof(buf));
+    yaffs_read(h, buf, sizeof(buf));
+    printf("Create File [%s] content: [%s]\n", full_name, buf);
+    yaffs_close(h);
+
+    return 0;
+}
+
+int rm(const char *mp, const char *name)
+{
+    char full_name[100]; 
+
+    if(name)
+        sprintf(full_name, "%s/%s", mp, name); 
+    else
+        strcpy(full_name, mp);
+    
+    printf("Remove %s\n", full_name);
+    return yaffs_rm(full_name, 1);
+}
+
+int ls(const char *mp, const char *name)
+{
+    int recursive = 1;
+    char full_name[100]; 
+
+    if(name)
+        sprintf(full_name, "%s/%s", mp, name); 
+    else
+        strcpy(full_name, mp);
+    
+    printf("List folder '%s' %s recursive:\n", full_name, recursive?"with":"without");
+    return yaffs_ls(full_name, recursive);
+}
+
+
+void dump_directory_tree_worker(const char *dname,int recursive)
+{
+    yaffs_DIR *d;
+    struct yaffs_dirent *de;
+    struct yaffs_stat s;
+    char str[1000];
+
+    d = yaffs_opendir(dname);
+
+    if(!d)
+    {
+        printf("opendir failed\n");
+    }
+    else
+    {
+        while((de = yaffs_readdir(d)) != NULL)
+        {
+            sprintf(str,"%s/%s",dname,de->d_name);
+
+            yaffs_lstat(str,&s);
+
+            printf("%s inode %d obj %x length %lld mode %X ",
+                str,s.st_ino,de->d_dont_use, s.st_size,s.st_mode);
+            switch(s.st_mode & S_IFMT)
+            {
+                case S_IFREG: printf("data file"); break;
+                case S_IFDIR: printf("directory"); break;
+                case S_IFLNK: printf("symlink -->");
+                              if(yaffs_readlink(str,str,100) < 0)
+                                printf("no alias");
+                              else
+                                printf("\"%s\"",str);
+                              break;
+                default: printf("unknown"); break;
+            }
+            printf("\n");
+
+            if((s.st_mode & S_IFMT) == S_IFDIR && recursive)
+                dump_directory_tree_worker(str,1);
+        }
+
+        yaffs_closedir(d);
+    }
+}
+
+
+static void dump_directory_tree(const char *dname)
+{   
+    dump_directory_tree_worker(dname,1);
+    printf("\n");
+    printf("Free space in %s is %d\n\n",dname,(int)yaffs_freespace(dname));
+}   
+
+void dumpDir(const char *dname)
+{  
+    dump_directory_tree_worker(dname,0);
+    printf("\n");
+    printf("Free space in %s is %d\n\n",dname,(int)yaffs_freespace(dname));
+}   
+
+
+void yaffs_test(const char *mountpt)
+{
+    yaffs_start_up();
+
+#if 0
+    yaffs_mount(mountpt);
+    ls(mountpt, NULL);
+
+    mkdir(mountpt, "foo");
+    mkfile(mountpt, "foo/f1");
+
+    return ;
+#endif
+
+    yaffs_format(mountpt,0,0,0);
+
+    yaffs_mount(mountpt);
+    printf("'%s' mounted\n", mountpt);
+
+    mkdir(mountpt, "foo");
+    mkfile(mountpt, "foo/f1");
+
+    mkfile(mountpt, "foo/f2");
+    mkfile(mountpt, "foo/f3");
+    mkfile(mountpt, "foo/f4");
+
+    mkdir(mountpt, "bar");
+    mkfile(mountpt, "bar/f1");
+    ls(mountpt, NULL);
+
+    rm(mountpt, "foo/f4");
+    rm(mountpt, "bar");
+    ls(mountpt, NULL);
+
+    printf("unmount and remount\n\n"); 
+    
+    /*  Unmount/remount yaffs_trace_mask */
+    yaffs_unmount(mountpt);
+    yaffs_mount(mountpt);
+    ls(mountpt, NULL);
+}
+
+int bootstrap_main(void)
+{
+    char *ptr = NULL;
+    int rv = -1;
+
+    console_serial_init();
+    printf("\b\n");
+    printf("\bBootstrap nandflash yaffs2 test Version 0.0.1\n");
+
+    /*  armboot_start is defined in the board-specific linker script */
+    mem_malloc_init (TEXT_BASE - CONFIG_SYS_MALLOC_LEN, CONFIG_SYS_MALLOC_LEN);
+
+    ptr = (char *)malloc(MALLOC_SIZE);
+    strncpy(ptr, "Hello World!\n", MALLOC_SIZE);
+    printf("Malloc address: %p, string: %s\n", ptr, ptr);
+    free(ptr);
+
+    yaffs_test(YAFFSFS_MNT_POINT);
+
+hang:
+    while(1)
+        ;
+
+    return 0;
+}
+
diff --git a/linux-bsp/asm-study/yaffs2/bootstrap.lds b/linux-bsp/asm-study/yaffs2/bootstrap.lds
new file mode 100644
index 0000000..810e0a7
--- /dev/null
+++ b/linux-bsp/asm-study/yaffs2/bootstrap.lds
@@ -0,0 +1,32 @@
+/********************************************************************************************
+ *        File:  bootstrap.lds
+ *     Version:  1.0.0
+ *   Copyright:  2011 (c) Guo Wenxue <guowenxue@gmail.com>
+ * Description:  This is the LD linker configure script for bootstrap 
+ *   ChangeLog:  1, Release initial version on "Tue Jul 12 16:43:18 CST 2011"
+ *
+ *******************************************************************************************/
+
+OUTPUT_FORMAT("elf32-littlearm", "elf32-littlearm", "elf32-littlearm")
+OUTPUT_ARCH(arm)
+ENTRY(_start)
+
+SECTIONS{
+    . = ALIGN(4);
+    .text   :
+    {
+      start.o   (.text)
+      *(.text)
+    }
+    . = ALIGN(4);
+    .rodata : { *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*))) }
+    . = ALIGN(4);
+    .rodata : { *(.rodata) }
+    . = ALIGN(4);
+    .data : { *(.data) }
+    . = ALIGN(4);
+    __bss_start = .;
+    .bss : { *(.bss) }
+    _end = .;
+}
+
diff --git a/linux-bsp/asm-study/yaffs2/bsp/eabi_compat.c b/linux-bsp/asm-study/yaffs2/bsp/eabi_compat.c
new file mode 100644
index 0000000..61949e3
--- /dev/null
+++ b/linux-bsp/asm-study/yaffs2/bsp/eabi_compat.c
@@ -0,0 +1,29 @@
+/*
+ * Utility functions needed for (some) EABI conformant tool chains.
+ *
+ * (C) Copyright 2009 Wolfgang Denk <wd@denx.de>
+ *
+ * This program is Free Software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ */
+
+#include <stdio.h>
+
+#if 1
+int raise (int signum)
+{
+//	printf("raise: Signal # %d caught\n", signum);
+	return 0;
+}
+
+/* Dummy function to avoid linker complaints */
+void __aeabi_unwind_cpp_pr0(void)
+{
+};
+#else
+void __aeabi_unwind_cpp_pr1(void)
+{
+};
+#endif
diff --git a/linux-bsp/asm-study/yaffs2/bsp/k9f2g08_api.c b/linux-bsp/asm-study/yaffs2/bsp/k9f2g08_api.c
new file mode 100644
index 0000000..1db8432
--- /dev/null
+++ b/linux-bsp/asm-study/yaffs2/bsp/k9f2g08_api.c
@@ -0,0 +1,276 @@
+/*
+|  ECC MAIN  | BAD  | RES  |       YAFFS_TAG       |
+|     4      |  4   |  8   |          48           |
+*/
+
+#include "k9f2g08_s3c.h"
+
+/* From yaffs_guts.h */
+#define YAFFS_OK    1
+#define YAFFS_FAIL  0
+
+
+int k9f2g08_init(void)
+{
+	return YAFFS_OK;
+}
+
+int k9f2g08_deinit(void)
+{
+	return YAFFS_OK;
+}
+
+static unsigned char wait_busy_status(void)
+{
+	unsigned char rc;
+
+	for (rc=0; rc <40; rc++);
+	bsp_nand_set_cs(0);
+	bsp_nand_write_cmd(0x70);  // read status
+	do {
+		rc = bsp_nand_read_data8();
+	} while ((rc & (1<<6)) == 0);
+	bsp_nand_set_cs(1);
+
+	return rc;
+}
+
+int k9f2g08_mark_block_bad(unsigned int blk_num)
+{
+	int row_addr = blk_num * 64;
+	int col_addr = 2048;
+
+	unsigned char status;
+
+	bsp_nand_set_cs(0);
+	bsp_nand_write_cmd(0x80);  // write command
+	bsp_nand_write_addr((unsigned char)(col_addr >> 0));
+	bsp_nand_write_addr((unsigned char)(col_addr >> 8));
+	bsp_nand_write_addr((unsigned char)(row_addr >> 0));
+	bsp_nand_write_addr((unsigned char)(row_addr >> 8));
+	bsp_nand_write_addr((unsigned char)(row_addr >> 16));
+
+	bsp_nand_write_data32(0xFFFFFFFF);
+	bsp_nand_write_data32(0x00000000);
+	bsp_nand_write_data32(0xFFFFFFFF);
+	bsp_nand_write_data32(0xFFFFFFFF);
+	bsp_nand_write_cmd(0x10);
+	bsp_nand_set_cs(1);
+
+	status = wait_busy_status();
+
+	return (status & (1<<0)) ? YAFFS_FAIL : YAFFS_OK;
+}
+
+int k9f2g08_write(unsigned int chunk, const unsigned char *dat, const unsigned char *spare, unsigned int spare_size)
+{
+	int i;
+	int col_addr;
+	unsigned char status;
+
+	if (dat) {
+		col_addr = 0;
+	} else {
+		col_addr = 2048;
+	}
+
+
+	bsp_nand_set_cs(0);
+	bsp_nand_write_cmd(0x80);  // write command
+	bsp_nand_write_addr((unsigned char)(col_addr >> 0));
+	bsp_nand_write_addr((unsigned char)(col_addr >> 8));
+	bsp_nand_write_addr((unsigned char)(chunk >> 0));
+	bsp_nand_write_addr((unsigned char)(chunk >> 8));
+	bsp_nand_write_addr((unsigned char)(chunk >> 16));
+
+	bsp_nand_start_main_ecc();
+	if (dat) {
+		for (i=0; i<2048; i++)
+			bsp_nand_write_data8(*dat++);
+	}
+
+	bsp_nand_stop_main_ecc();
+
+	bsp_nand_write_data32(bsp_nand_read_spare_ecc0());
+	bsp_nand_write_data32(0xFFFFFFFF);
+	bsp_nand_write_data32(0xFFFFFFFF);
+	bsp_nand_write_data32(0xFFFFFFFF);
+
+	if (spare) {
+		for (i=0; i<spare_size; i++)
+			bsp_nand_write_data8(*spare++);
+	}
+
+	bsp_nand_write_cmd(0x10);
+	bsp_nand_set_cs(1);
+
+	status = wait_busy_status();
+
+	return (status & (1<<0)) ? YAFFS_FAIL : YAFFS_OK;
+}
+
+int k9f2g08_read(unsigned int chunk, unsigned char *dat, unsigned char *spare, unsigned int spare_size, int *eccStatus)
+{
+	int i;
+	int col_addr;
+	unsigned char *p = dat;
+	unsigned int ecc = 0;
+	int err_bit;
+	int err_byte;
+
+	if (dat) {
+		col_addr = 0;
+	} else {
+		col_addr = 2048 + 16;
+	}
+
+
+	bsp_nand_set_cs(0);
+	bsp_nand_write_cmd(0x00);  // read command
+	bsp_nand_write_addr((unsigned char)(col_addr >> 0));
+	bsp_nand_write_addr((unsigned char)(col_addr >> 8));
+	bsp_nand_write_addr((unsigned char)(chunk >> 0));
+	bsp_nand_write_addr((unsigned char)(chunk >> 8));
+	bsp_nand_write_addr((unsigned char)(chunk >> 16));
+	bsp_nand_write_cmd(0x30);  // read
+	bsp_nand_wait_busy();
+
+	if (dat) {
+		bsp_nand_start_main_ecc();
+		for (i=0; i<2048; i++)
+			*p++ = bsp_nand_read_data8();
+
+		bsp_nand_stop_main_ecc();
+
+		ecc = bsp_nand_read_data32();
+
+		bsp_nand_read_data32();
+		bsp_nand_read_data32();
+		bsp_nand_read_data32();
+	}
+	if (spare) {
+		p = spare;
+		for (i=0; i<spare_size; i++)
+			*p++ = bsp_nand_read_data8();
+	}
+
+	bsp_nand_set_cs(1);
+
+	if (dat) {
+		i = bsp_nand_main_check_ecc(ecc, &err_byte, &err_bit);
+		if (i == 0) {
+			*eccStatus = 0;
+			return 0;
+		}
+
+		if (i < 0) {
+			*eccStatus = -1;
+			return 0;
+		}
+
+		*eccStatus = 1;
+		dat[err_byte] ^= (1<<err_bit);
+	}
+
+	return YAFFS_OK;
+}
+
+int k9f2g08_erase_block(unsigned int blk_num)
+{
+	unsigned char status;
+	int chunk = blk_num * 64;
+
+	bsp_nand_set_cs(0);
+	bsp_nand_write_cmd(0x60);  // erase command
+	bsp_nand_write_addr((unsigned char)(chunk >> 0));
+	bsp_nand_write_addr((unsigned char)(chunk >> 8));
+	bsp_nand_write_addr((unsigned char)(chunk >> 16));
+	bsp_nand_write_cmd(0xD0);  // erase
+	bsp_nand_set_cs(1);
+
+	status = wait_busy_status();
+	return (status & (1<<0)) ? YAFFS_FAIL : YAFFS_OK;
+}
+
+int k9f2g08_is_block_ok(unsigned int blk_num)
+{
+	int chunk = blk_num * 64;
+	int col_addr = 2048 + 4;
+
+	bsp_nand_set_cs(0);
+	bsp_nand_write_cmd(0x00);  // read command
+	bsp_nand_write_addr((unsigned char)(col_addr >> 0));
+	bsp_nand_write_addr((unsigned char)(col_addr >> 8));
+	bsp_nand_write_addr((unsigned char)(chunk >> 0));
+	bsp_nand_write_addr((unsigned char)(chunk >> 8));
+	bsp_nand_write_addr((unsigned char)(chunk >> 16));
+	bsp_nand_write_cmd(0x30);  // read
+	bsp_nand_wait_busy();
+
+	int tmp = bsp_nand_read_data32();
+	bsp_nand_set_cs(1);
+
+	if (tmp == 0xFFFFFFFF) {
+		return 1;
+	}
+	return 0;
+}
+
+
+int k9f2g08_read_id(unsigned int *id)
+{
+	int rc = -1;
+	bsp_nand_set_cs(0);
+	bsp_nand_write_cmd(0x90);  // read command
+	bsp_nand_write_addr((unsigned char)0);
+	do {
+		if ((rc = bsp_nand_read_data8()) != 0xEC)
+			break;
+		*id = bsp_nand_read_data32();
+		rc = 0;
+	} while(0);
+
+	bsp_nand_set_cs(1);
+
+	return rc;
+}
+
+int k9f2g08_read_ll(unsigned int chunk, unsigned char *dat, unsigned char *spare)
+{
+	int i;
+	int col_addr;
+	unsigned char *p;
+
+	if (dat) {
+		col_addr = 0;
+	} else {
+		col_addr = 2048;
+	}
+
+
+	bsp_nand_set_cs(0);
+	bsp_nand_write_cmd(0x00);  // read command
+	bsp_nand_write_addr((unsigned char)(col_addr >> 0));
+	bsp_nand_write_addr((unsigned char)(col_addr >> 8));
+	bsp_nand_write_addr((unsigned char)(chunk >> 0));
+	bsp_nand_write_addr((unsigned char)(chunk >> 8));
+	bsp_nand_write_addr((unsigned char)(chunk >> 16));
+	bsp_nand_write_cmd(0x30);  // read
+
+	bsp_nand_wait_busy();
+
+	if (dat) {
+		p = dat;
+		for (i=0; i<2048; i++)
+			*p++ = bsp_nand_read_data8();
+	}
+	if (spare) {
+		p = spare;
+		for (i=0; i<64; i++)
+			*p++ = bsp_nand_read_data8();
+	}
+
+	bsp_nand_set_cs(1);
+
+	return 1;
+}
diff --git a/linux-bsp/asm-study/yaffs2/bsp/k9f2g08_api.h b/linux-bsp/asm-study/yaffs2/bsp/k9f2g08_api.h
new file mode 100644
index 0000000..e3f7af8
--- /dev/null
+++ b/linux-bsp/asm-study/yaffs2/bsp/k9f2g08_api.h
@@ -0,0 +1,14 @@
+#ifndef __K9F2G08_API_H__
+#define __K9F2G08_API_H__
+
+int k9f2g08_init(void);
+int k9f2g08_deinit(void);
+int k9f2g08_mark_block_bad(unsigned int blk_num);
+int k9f2g08_write(unsigned int chunk, const unsigned char *dat, const unsigned char *spare, unsigned int spare_size);
+int k9f2g08_read(unsigned int chunk, unsigned char *dat, unsigned char *spare, unsigned int spare_size, int *eccStatus);
+int k9f2g08_read_ll(unsigned int chunk, unsigned char *dat, unsigned char *spare);
+int k9f2g08_erase_block(unsigned int blk_num);
+int k9f2g08_is_block_ok(unsigned int blk_num);
+int k9f2g08_read_id(unsigned int *id);
+
+#endif  // __K9F2G08_API_H__
diff --git a/linux-bsp/asm-study/yaffs2/bsp/k9f2g08_s3c.h b/linux-bsp/asm-study/yaffs2/bsp/k9f2g08_s3c.h
new file mode 100644
index 0000000..a627766
--- /dev/null
+++ b/linux-bsp/asm-study/yaffs2/bsp/k9f2g08_s3c.h
@@ -0,0 +1,177 @@
+#ifndef __K9F2G08_S3C_H__
+#define __K9F2G08_S3C_H__
+
+#include "s3c2440.h"
+
+static inline void bsp_init_nand(void)
+{
+	unsigned int  reg;
+
+	struct s3c2440_clock_power *clkpwr = s3c2440_get_base_clock_power();
+ 	clkpwr->CLKCON |= (1<<4);
+
+	struct s3c2440_gpio *gpio = s3c2440_get_base_gpio();
+	struct s3c2440_nand *nand = s3c2440_get_base_nand();
+
+	reg = gpio->GPACON;
+	reg |= (1<<22) | (1<<20) | (1<<19) | (1<<18) | (1<<17);
+	gpio->GPACON = reg;
+
+	nand->NFCONF = (1<<12) | (1<<8) | (1<<4) | (1<<3) |(1<<2) | (1<<5) | (0<<0);
+	nand->NFCONT = 3;
+}
+
+static inline void bsp_nand_set_cs(int level)
+{
+	struct s3c2440_nand *nand = s3c2440_get_base_nand();
+	if (level == 0) {
+		nand->NFCONT &= ~(1<<1);
+//		while (nand->NFSTAT & (1<<1));
+	} else {
+		nand->NFCONT |= 1<<1;
+//		while ((nand->NFSTAT & (1<<1)) == 0);
+	}
+}
+
+static inline void bsp_nand_start_main_ecc(void)
+{
+	struct s3c2440_nand *nand = s3c2440_get_base_nand();
+	nand->NFCONT |= (1<<6) | (1<<5);  // unlock all
+	nand->NFCONT |= (1<<4);  // init ecc
+	nand->NFCONT &= ~(1<<6);  // lock spare
+}
+
+static inline void bsp_nand_stop_main_ecc(void)
+{
+	struct s3c2440_nand *nand = s3c2440_get_base_nand();
+	nand->NFCONT |= (1<<5);  // lock main
+}
+
+static inline void bsp_nand_start_spare_ecc(void)
+{
+	struct s3c2440_nand *nand = s3c2440_get_base_nand();
+	nand->NFCONT &= ~(1<<6); // unlock spare
+}
+
+static inline void bsp_nand_stop_spare_ecc(void)
+{
+	struct s3c2440_nand *nand = s3c2440_get_base_nand();
+	nand->NFCONT |= (1<<6); // lock spare
+}
+
+static inline int bsp_nand_spare_check_ecc(unsigned short ecc, int *err_byte, int *err_bit)
+{
+	struct s3c2440_nand *nand = s3c2440_get_base_nand();
+	unsigned int ecc_wr = ((ecc & 0xFF00) << 8) | (ecc & 0x00FF);
+
+	nand->NFSECCD = ecc_wr;
+	int err = nand->NFESTAT0;
+
+	if ((err & (3<<2)) == (0<<2))  // no err
+		return 0;
+
+
+	if ((err & (3<<2)) == (1<<2)) {  // 1 bit err
+		*err_byte = (err >> 21) & 0x0F;
+		*err_bit = (err >> 18) & 0x07;
+		return 1;
+	}
+
+	return -1;
+
+}
+
+static inline int bsp_nand_main_check_ecc(unsigned int ecc, int *err_byte, int *err_bit)
+{
+	struct s3c2440_nand *nand = s3c2440_get_base_nand();
+
+	unsigned int ecc_wr = ((ecc & 0xFF00) << 8) | (ecc & 0x00FF);
+	nand->NFMECCD0 = ecc_wr;
+
+	ecc_wr = ((ecc & 0xFF000000) >> 8) | ((ecc & 0x00FF0000) >> 16);
+	nand->NFMECCD1 = ecc_wr;
+
+	int err = nand->NFESTAT0;
+
+	if ((err & (3<<0)) == (0<<0))  // no err
+		return 0;
+
+
+	if ((err & (3<<0)) == (1<<0)) {  // no err
+		*err_byte = (err >> 7) & 0x7FF;
+		*err_bit = (err >> 4) & 0x07;
+		return 1;
+	}
+
+	return -1;
+}
+
+
+static inline void bsp_nand_write_cmd(unsigned char cmd)
+{
+	struct s3c2440_nand *nand = s3c2440_get_base_nand();
+	nand->NFCMD = cmd;
+}
+
+
+static inline void bsp_nand_write_addr(unsigned char addr)
+{
+	struct s3c2440_nand *nand = s3c2440_get_base_nand();
+	nand->NFADDR = addr;
+}
+
+static inline void bsp_nand_write_data32(unsigned int dat)
+{
+	*(volatile unsigned int *)(&(s3c2440_get_base_nand()->NFDATA)) = dat;
+}
+
+
+static inline void bsp_nand_write_data16(unsigned short dat)
+{
+	*(volatile unsigned short *)(&(s3c2440_get_base_nand()->NFDATA)) = dat;
+}
+
+static inline void bsp_nand_write_data8(unsigned char dat)
+{
+	*(volatile unsigned char *)(&(s3c2440_get_base_nand()->NFDATA)) = dat;
+}
+
+
+static inline unsigned int bsp_nand_read_data32(void)
+{
+	return *(volatile unsigned int *)(&(s3c2440_get_base_nand()->NFDATA));
+}
+
+
+static inline unsigned short bsp_nand_read_data16(void)
+{
+	return *(volatile unsigned short *)(&(s3c2440_get_base_nand()->NFDATA));
+}
+
+static inline unsigned char bsp_nand_read_data8(void)
+{
+	return *(volatile unsigned char *)(&(s3c2440_get_base_nand()->NFDATA));
+}
+
+static inline unsigned short bsp_nand_read_spare_ecc0(void)
+{
+	struct s3c2440_nand *nand = s3c2440_get_base_nand();
+	return nand->NFSECC & 0xFFFF;
+}
+
+static inline unsigned int bsp_nand_read_main_ecc0(void)
+{
+	struct s3c2440_nand *nand = s3c2440_get_base_nand();
+	return nand->NFMECC0;
+}
+
+
+static inline void bsp_nand_wait_busy(void)
+{
+	int i;
+	for (i=10; i>0; i--);
+	struct s3c2440_nand *nand = s3c2440_get_base_nand();
+	while ((nand->NFSTAT & (1<<0)) == 0);
+}
+
+#endif //__K9F2G08_S3C_H__
diff --git a/linux-bsp/asm-study/yaffs2/bsp/makefile b/linux-bsp/asm-study/yaffs2/bsp/makefile
new file mode 100644
index 0000000..be21cdc
--- /dev/null
+++ b/linux-bsp/asm-study/yaffs2/bsp/makefile
@@ -0,0 +1,102 @@
+#*********************************************************************************
+#      Copyright:  (C) 2012 CoherentPlus Sdn. Bhd.
+#                  All rights reserved.
+#
+#       Filename:  Makefile
+#    Description:  This is the common subdir Makefile which to compile all the C
+#                  source code to object files and then generate the shared or 
+#                  static library named lib$(FOLDER_NAME).a orlib $(FOLDER_NAME).so,
+#                  which depends on the variable $LINK_MODE.
+#                      
+#        Version:  1.0.0(10/08/2011~)
+#                  Author:  Guo Wenxue <guowenxue@gmail.com>
+#      ChangeLog:  1, Release initial version on "10/08/2011 01:29:33 AM"
+#                       
+#********************************************************************************/
+
+PWD=$(shell pwd)
+LOCAL_COMPILE=YES
+LINK_MODE=STATIC
+
+#If wanna compile in the subdir, not called by top makefile, uncomment it
+ifneq (${TOP_COMPILE}, YES) 
+LOCAL_COMPILE=YES
+endif
+
+LIBNAME=$(shell basename ${PWD})
+STALIB=lib${LIBNAME}.a
+DYNLIB=lib${LIBNAME}.so
+
+VPATH= .
+C_SRCS = $(wildcard ${VPATH}/*.c)
+AS_SRCS = $(wildcard ${VPATH}/*.S)
+OBJS = $(patsubst %.c,%.o,$(C_SRCS))
+OBJS += $(patsubst %.S,%.o,$(AS_SRCS))
+
+#======================================================
+#  ---> Doesn't call by top makefile, compile by local
+#======================================================
+ifeq (${LOCAL_COMPILE}, YES)
+ARCH?=arm920t
+#ARCH?=i386
+CFLAGS+=-fPIC
+TMP=$(shell echo $(ARCH) | tr "[A-Z]" "[a-z]")
+ifneq (,$(filter i386,$(TMP)))
+    CROSS_COMPILE=
+else
+    CROSS_COMPILE=/opt/xtools/arm920t/bin/arm-linux-
+endif
+
+PRJDIR?=$(shell pwd)
+CFLAGS+=-I${PRJDIR}
+CC = ${CROSS_COMPILE}gcc
+AR = ${CROSS_COMPILE}ar
+
+endif #End local compile
+
+ifeq ("${LINK_MODE}", "STATIC")
+	LIBS = ${STALIB} 
+else 
+	LIBS=${DYNLIB}
+endif
+
+all: entry ${LIBS} install
+
+entry: 
+	@echo " ";
+	@echo " =========================================================";
+	@echo " **     Compile subdir ${LIBNAME} for ${ARCH}             ";
+	@echo " =========================================================";
+
+#$(LD) -g --relocatable $(OBJS) -o lib${LIBNAME}.o
+${STALIB}:	$(OBJS) 
+	$(AR) -rcu $@ $(OBJS)
+
+${DYNLIB}:   $(OBJS) 
+	$(CC) -fPIC -shared -o $@ $(OBJS)
+
+%.o: %.S
+	$(CC) $(AFLAGS) -c -o $@ $<
+
+%.o : %.c
+	$(CC) -c $< $(CFLAGS)
+
+tag: 
+	@ctags --c-kinds=+defglmnstuvx --langmap=c:.c.h.ho.hem.het.hec.hev.him.hit.hic.hiv -R .  
+	@cscope -Rbq
+
+install:
+	@if [ ! -z "${LIBS_PATH}" ] ; then \
+		mkdir -p ${LIBS_PATH} ; \
+		cp ${LIBS} ${LIBS_PATH}; \
+	fi;
+
+
+clean:
+	@rm -f *.o
+	@rm -rf *.gdb *.a *.so
+
+distclean: clean
+	@rm -f  tags cscope*
+
+.PHONY: clean entry
diff --git a/linux-bsp/asm-study/yaffs2/bsp/s3c2440.h b/linux-bsp/asm-study/yaffs2/bsp/s3c2440.h
new file mode 100644
index 0000000..0a46bc9
--- /dev/null
+++ b/linux-bsp/asm-study/yaffs2/bsp/s3c2440.h
@@ -0,0 +1,646 @@
+#ifndef __S3C2440_H__
+#define __S3C2440_H__
+
+#define S3C2440_UART_CHANNELS	3
+#define S3C2440_SPI_CHANNELS	2
+
+/* Memory controller (see manual chapter 5) */
+struct s3c2440_memctl {
+	volatile unsigned int	BWSCON;
+	volatile unsigned int	BANKCON[8];
+	volatile unsigned int	REFRESH;
+	volatile unsigned int	BANKSIZE;
+	volatile unsigned int	MRSRB6;
+	volatile unsigned int	MRSRB7;
+};
+
+
+/* USB HOST (see manual chapter 12) */
+struct s3c2440_usb_host {
+	volatile unsigned int	HcRevision;
+	volatile unsigned int	HcControl;
+	volatile unsigned int	HcCommonStatus;
+	volatile unsigned int	HcInterruptStatus;
+	volatile unsigned int	HcInterruptEnable;
+	volatile unsigned int	HcInterruptDisable;
+	volatile unsigned int	HcHCCA;
+	volatile unsigned int	HcPeriodCuttendED;
+	volatile unsigned int	HcControlHeadED;
+	volatile unsigned int	HcControlCurrentED;
+	volatile unsigned int	HcBulkHeadED;
+	volatile unsigned int	HcBuldCurrentED;
+	volatile unsigned int	HcDoneHead;
+	volatile unsigned int	HcRmInterval;
+	volatile unsigned int	HcFmRemaining;
+	volatile unsigned int	HcFmNumber;
+	volatile unsigned int	HcPeriodicStart;
+	volatile unsigned int	HcLSThreshold;
+	volatile unsigned int	HcRhDescriptorA;
+	volatile unsigned int	HcRhDescriptorB;
+	volatile unsigned int	HcRhStatus;
+	volatile unsigned int	HcRhPortStatus1;
+	volatile unsigned int	HcRhPortStatus2;
+};
+
+
+/* INTERRUPT (see manual chapter 14) */
+struct s3c2440_interrupt {
+	volatile unsigned int	SRCPND;
+	volatile unsigned int	INTMOD;
+	volatile unsigned int	INTMSK;
+	volatile unsigned int	PRIORITY;
+	volatile unsigned int	INTPND;
+	volatile unsigned int	INTOFFSET;
+	volatile unsigned int	SUBSRCPND;
+	volatile unsigned int	INTSUBMSK;
+};
+
+
+/* DMAS (see manual chapter 8) */
+struct s3c2440_dma {
+	volatile unsigned int	DISRC;
+	volatile unsigned int	DISRCC;
+	volatile unsigned int	DIDST;
+	volatile unsigned int	DIDSTC;
+	volatile unsigned int	DCON;
+	volatile unsigned int	DSTAT;
+	volatile unsigned int	DCSRC;
+	volatile unsigned int	DCDST;
+	volatile unsigned int	DMASKTRIG;
+	volatile unsigned int	res[7];
+};
+
+struct s3c2440_dmas {
+	struct s3c2440_dma	dma[4];
+};
+
+
+struct s3c2440_clock_power {
+	volatile unsigned int	LOCKTIME;
+	volatile unsigned int	MPLLCON;
+	volatile unsigned int	UPLLCON;
+	volatile unsigned int	CLKCON;
+	volatile unsigned int	CLKSLOW;
+	volatile unsigned int	CLKDIVN;
+	volatile unsigned int CAMDIVN;
+};
+
+
+/* LCD CONTROLLER (see manual chapter 15) */
+struct s3c2440_lcd {
+	volatile unsigned int	LCDCON1;
+	volatile unsigned int	LCDCON2;
+	volatile unsigned int	LCDCON3;
+	volatile unsigned int	LCDCON4;
+	volatile unsigned int	LCDCON5;
+	volatile unsigned int	LCDSADDR1;
+	volatile unsigned int	LCDSADDR2;
+	volatile unsigned int	LCDSADDR3;
+	volatile unsigned int	REDLUT;
+	volatile unsigned int	GREENLUT;
+	volatile unsigned int	BLUELUT;
+	volatile unsigned int	res[8];
+	volatile unsigned int	DITHMODE;
+	volatile unsigned int	TPAL;
+	volatile unsigned int	LCDINTPND;
+	volatile unsigned int	LCDSRCPND;
+	volatile unsigned int	LCDINTMSK;
+	volatile unsigned int	TCONSEL;
+};
+
+
+/* NAND FLASH (see S3C2440 manual chapter 6) */
+struct s3c2440_nand {
+	volatile unsigned int	NFCONF;
+	volatile unsigned int	NFCONT;
+	volatile unsigned int	NFCMD;
+	volatile unsigned int	NFADDR;
+	volatile unsigned int	NFDATA;
+	volatile unsigned int	NFMECCD0;
+	volatile unsigned int	NFMECCD1;
+	volatile unsigned int	NFSECCD;
+	volatile unsigned int	NFSTAT;
+	volatile unsigned int	NFESTAT0;
+	volatile unsigned int	NFESTAT1;
+	volatile unsigned int	NFMECC0;
+	volatile unsigned int	NFMECC1;
+	volatile unsigned int	NFSECC;
+	volatile unsigned int	NFSBLK;
+	volatile unsigned int	NFEBLK;
+};
+
+
+/* UART (see manual chapter 11) */
+struct s3c2440_uart {
+	volatile unsigned int	ULCON;
+	volatile unsigned int	UCON;
+	volatile unsigned int	UFCON;
+	volatile unsigned int	UMCON;
+	volatile unsigned int	UTRSTAT;
+	volatile unsigned int	UERSTAT;
+	volatile unsigned int	UFSTAT;
+	volatile unsigned int	UMSTAT;
+#ifdef __BIG_ENDIAN
+	volatile unsigned char	res1[3];
+	volatile unsigned char	UTXH;
+	volatile unsigned char	res2[3];
+	volatile unsigned char	URXH;
+#else /* Little Endian */
+	volatile unsigned char	UTXH;
+	volatile unsigned char	res1[3];
+	volatile unsigned char	URXH;
+	volatile unsigned char	res2[3];
+#endif
+	volatile unsigned int	UBRDIV;
+};
+
+
+/* PWM TIMER (see manual chapter 10) */
+struct s3c2440_timer {
+	volatile unsigned int	TCNTB;
+	volatile unsigned int	TCMPB;
+	volatile unsigned int	TCNTO;
+};
+
+struct s3c2440_timers {
+	volatile unsigned int	TCFG0;
+	volatile unsigned int	TCFG1;
+	volatile unsigned int	TCON;
+	struct s3c2440_timer	ch[4];
+	volatile unsigned int	TCNTB4;
+	volatile unsigned int	TCNTO4;
+};
+
+
+/* USB DEVICE (see manual chapter 13) */
+struct s3c2440_usb_dev_fifos {
+#ifdef __BIG_ENDIAN
+	volatile unsigned char	res[3];
+	volatile unsigned char	EP_FIFO_REG;
+#else /*  little endian */
+	volatile unsigned char	EP_FIFO_REG;
+	volatile unsigned char	res[3];
+#endif
+};
+
+struct s3c2440_usb_dev_dmas {
+#ifdef __BIG_ENDIAN
+	volatile unsigned char	res1[3];
+	volatile unsigned char	EP_DMA_CON;
+	volatile unsigned char	res2[3];
+	volatile unsigned char	EP_DMA_UNIT;
+	volatile unsigned char	res3[3];
+	volatile unsigned char	EP_DMA_FIFO;
+	volatile unsigned char	res4[3];
+	volatile unsigned char	EP_DMA_TTC_L;
+	volatile unsigned char	res5[3];
+	volatile unsigned char	EP_DMA_TTC_M;
+	volatile unsigned char	res6[3];
+	volatile unsigned char	EP_DMA_TTC_H;
+#else /*  little endian */
+	volatile unsigned char	EP_DMA_CON;
+	volatile unsigned char	res1[3];
+	volatile unsigned char	EP_DMA_UNIT;
+	volatile unsigned char	res2[3];
+	volatile unsigned char	EP_DMA_FIFO;
+	volatile unsigned char	res3[3];
+	volatile unsigned char	EP_DMA_TTC_L;
+	volatile unsigned char	res4[3];
+	volatile unsigned char	EP_DMA_TTC_M;
+	volatile unsigned char	res5[3];
+	volatile unsigned char	EP_DMA_TTC_H;
+	volatile unsigned char	res6[3];
+#endif
+};
+
+struct s3c2440_usb_device {
+#ifdef __BIG_ENDIAN
+	volatile unsigned char	res1[3];
+	volatile unsigned char	FUNC_ADDR_REG;
+	volatile unsigned char	res2[3];
+	volatile unsigned char	PWR_REG;
+	volatile unsigned char	res3[3];
+	volatile unsigned char	EP_INT_REG;
+	volatile unsigned char	res4[15];
+	volatile unsigned char	USB_INT_REG;
+	volatile unsigned char	res5[3];
+	volatile unsigned char	EP_INT_EN_REG;
+	volatile unsigned char	res6[15];
+	volatile unsigned char	USB_INT_EN_REG;
+	volatile unsigned char	res7[3];
+	volatile unsigned char	FRAME_NUM1_REG;
+	volatile unsigned char	res8[3];
+	volatile unsigned char	FRAME_NUM2_REG;
+	volatile unsigned char	res9[3];
+	volatile unsigned char	INDEX_REG;
+	volatile unsigned char	res10[7];
+	volatile unsigned char	MAXP_REG;
+	volatile unsigned char	res11[3];
+	volatile unsigned char	EP0_CSR_IN_CSR1_REG;
+	volatile unsigned char	res12[3];
+	volatile unsigned char	IN_CSR2_REG;
+	volatile unsigned char	res13[7];
+	volatile unsigned char	OUT_CSR1_REG;
+	volatile unsigned char	res14[3];
+	volatile unsigned char	OUT_CSR2_REG;
+	volatile unsigned char	res15[3];
+	volatile unsigned char	OUT_FIFO_CNT1_REG;
+	volatile unsigned char	res16[3];
+	volatile unsigned char	OUT_FIFO_CNT2_REG;
+#else /*  little endian */
+	volatile unsigned char	FUNC_ADDR_REG;
+	volatile unsigned char	res1[3];
+	volatile unsigned char	PWR_REG;
+	volatile unsigned char	res2[3];
+	volatile unsigned char	EP_INT_REG;
+	volatile unsigned char	res3[15];
+	volatile unsigned char	USB_INT_REG;
+	volatile unsigned char	res4[3];
+	volatile unsigned char	EP_INT_EN_REG;
+	volatile unsigned char	res5[15];
+	volatile unsigned char	USB_INT_EN_REG;
+	volatile unsigned char	res6[3];
+	volatile unsigned char	FRAME_NUM1_REG;
+	volatile unsigned char	res7[3];
+	volatile unsigned char	FRAME_NUM2_REG;
+	volatile unsigned char	res8[3];
+	volatile unsigned char	INDEX_REG;
+	volatile unsigned char	res9[7];
+	volatile unsigned char	MAXP_REG;
+	volatile unsigned char	res10[7];
+	volatile unsigned char	EP0_CSR_IN_CSR1_REG;
+	volatile unsigned char	res11[3];
+	volatile unsigned char	IN_CSR2_REG;
+	volatile unsigned char	res12[3];
+	volatile unsigned char	OUT_CSR1_REG;
+	volatile unsigned char	res13[7];
+	volatile unsigned char	OUT_CSR2_REG;
+	volatile unsigned char	res14[3];
+	volatile unsigned char	OUT_FIFO_CNT1_REG;
+	volatile unsigned char	res15[3];
+	volatile unsigned char	OUT_FIFO_CNT2_REG;
+	volatile unsigned char	res16[3];
+#endif /*  __BIG_ENDIAN */
+	struct s3c2440_usb_dev_fifos	fifo[5];
+	struct s3c2440_usb_dev_dmas	dma[5];
+};
+
+
+/* WATCH DOG TIMER (see manual chapter 18) */
+struct s3c2440_watchdog {
+	volatile unsigned int	WTCON;
+	volatile unsigned int	WTDAT;
+	volatile unsigned int	WTCNT;
+};
+
+
+/* IIC (see manual chapter 20) */
+struct s3c2440_i2c {
+	volatile unsigned int	IICCON;
+	volatile unsigned int	IICSTAT;
+	volatile unsigned int	IICADD;
+	volatile unsigned int	IICDS;
+};
+
+
+/* IIS (see manual chapter 21) */
+struct s3c2440_i2s {
+#ifdef __BIG_ENDIAN
+	volatile unsigned short	res1;
+	volatile unsigned short	IISCON;
+	volatile unsigned short	res2;
+	volatile unsigned short	IISMOD;
+	volatile unsigned short	res3;
+	volatile unsigned short	IISPSR;
+	volatile unsigned short	res4;
+	volatile unsigned short	IISFCON;
+	volatile unsigned short	res5;
+	volatile unsigned short	IISFIFO;
+#else /*  little endian */
+	volatile unsigned short	IISCON;
+	volatile unsigned short	res1;
+	volatile unsigned short	IISMOD;
+	volatile unsigned short	res2;
+	volatile unsigned short	IISPSR;
+	volatile unsigned short	res3;
+	volatile unsigned short	IISFCON;
+	volatile unsigned short	res4;
+	volatile unsigned short	IISFIFO;
+	volatile unsigned short	res5;
+#endif
+};
+
+
+/* I/O PORT (see manual chapter 9) */
+struct s3c2440_gpio {
+	volatile unsigned int	GPACON;
+	volatile unsigned int	GPADAT;
+	volatile unsigned int	res1[2];
+	volatile unsigned int	GPBCON;
+	volatile unsigned int	GPBDAT;
+	volatile unsigned int	GPBUP;
+	volatile unsigned int	res2;
+	volatile unsigned int	GPCCON;
+	volatile unsigned int	GPCDAT;
+	volatile unsigned int	GPCUP;
+	volatile unsigned int	res3;
+	volatile unsigned int	GPDCON;
+	volatile unsigned int	GPDDAT;
+	volatile unsigned int	GPDUP;
+	volatile unsigned int	res4;
+	volatile unsigned int	GPECON;
+	volatile unsigned int	GPEDAT;
+	volatile unsigned int	GPEUP;
+	volatile unsigned int	res5;
+	volatile unsigned int	GPFCON;
+	volatile unsigned int	GPFDAT;
+	volatile unsigned int	GPFUP;
+	volatile unsigned int	res6;
+	volatile unsigned int	GPGCON;
+	volatile unsigned int	GPGDAT;
+	volatile unsigned int	GPGUP;
+	volatile unsigned int	res7;
+	volatile unsigned int	GPHCON;
+	volatile unsigned int	GPHDAT;
+	volatile unsigned int	GPHUP;
+	volatile unsigned int	res8;
+
+	volatile unsigned int	MISCCR;
+	volatile unsigned int	DCLKCON;
+	volatile unsigned int	EXTINT0;
+	volatile unsigned int	EXTINT1;
+	volatile unsigned int	EXTINT2;
+	volatile unsigned int	EINTFLT0;
+	volatile unsigned int	EINTFLT1;
+	volatile unsigned int	EINTFLT2;
+	volatile unsigned int	EINTFLT3;
+	volatile unsigned int	EINTMASK;
+	volatile unsigned int	EINTPEND;
+	volatile unsigned int	GSTATUS0;
+	volatile unsigned int	GSTATUS1;
+	volatile unsigned int	GSTATUS2;
+	volatile unsigned int	GSTATUS3;
+	volatile unsigned int	GSTATUS4;
+};
+
+
+/* RTC (see manual chapter 17) */
+struct s3c2440_rtc {
+#ifdef __BIG_ENDIAN
+	volatile unsigned char	res1[67];
+	volatile unsigned char	RTCCON;
+	volatile unsigned char	res2[3];
+	volatile unsigned char	TICNT;
+	volatile unsigned char	res3[11];
+	volatile unsigned char	RTCALM;
+	volatile unsigned char	res4[3];
+	volatile unsigned char	ALMSEC;
+	volatile unsigned char	res5[3];
+	volatile unsigned char	ALMMIN;
+	volatile unsigned char	res6[3];
+	volatile unsigned char	ALMHOUR;
+	volatile unsigned char	res7[3];
+	volatile unsigned char	ALMDATE;
+	volatile unsigned char	res8[3];
+	volatile unsigned char	ALMMON;
+	volatile unsigned char	res9[3];
+	volatile unsigned char	ALMYEAR;
+	volatile unsigned char	res10[3];
+	volatile unsigned char	RTCRST;
+	volatile unsigned char	res11[3];
+	volatile unsigned char	BCDSEC;
+	volatile unsigned char	res12[3];
+	volatile unsigned char	BCDMIN;
+	volatile unsigned char	res13[3];
+	volatile unsigned char	BCDHOUR;
+	volatile unsigned char	res14[3];
+	volatile unsigned char	BCDDATE;
+	volatile unsigned char	res15[3];
+	volatile unsigned char	BCDDAY;
+	volatile unsigned char	res16[3];
+	volatile unsigned char	BCDMON;
+	volatile unsigned char	res17[3];
+	volatile unsigned char	BCDYEAR;
+#else /*  little endian */
+	volatile unsigned char	res0[64];
+	volatile unsigned char	RTCCON;
+	volatile unsigned char	res1[3];
+	volatile unsigned char	TICNT;
+	volatile unsigned char	res2[11];
+	volatile unsigned char	RTCALM;
+	volatile unsigned char	res3[3];
+	volatile unsigned char	ALMSEC;
+	volatile unsigned char	res4[3];
+	volatile unsigned char	ALMMIN;
+	volatile unsigned char	res5[3];
+	volatile unsigned char	ALMHOUR;
+	volatile unsigned char	res6[3];
+	volatile unsigned char	ALMDATE;
+	volatile unsigned char	res7[3];
+	volatile unsigned char	ALMMON;
+	volatile unsigned char	res8[3];
+	volatile unsigned char	ALMYEAR;
+	volatile unsigned char	res9[3];
+	volatile unsigned char	RTCRST;
+	volatile unsigned char	res10[3];
+	volatile unsigned char	BCDSEC;
+	volatile unsigned char	res11[3];
+	volatile unsigned char	BCDMIN;
+	volatile unsigned char	res12[3];
+	volatile unsigned char	BCDHOUR;
+	volatile unsigned char	res13[3];
+	volatile unsigned char	BCDDATE;
+	volatile unsigned char	res14[3];
+	volatile unsigned char	BCDDAY;
+	volatile unsigned char	res15[3];
+	volatile unsigned char	BCDMON;
+	volatile unsigned char	res16[3];
+	volatile unsigned char	BCDYEAR;
+	volatile unsigned char	res17[3];
+#endif
+};
+
+
+/* ADC (see manual chapter 16) */
+struct s3c2440_adc {
+	volatile unsigned int	ADCCON;
+	volatile unsigned int	ADCTSC;
+	volatile unsigned int	ADCDLY;
+	volatile unsigned int	ADCDAT0;
+	volatile unsigned int	ADCDAT1;
+	volatile unsigned int ADCUPDN;
+};
+
+
+/* SPI (see manual chapter 22) */
+struct s3c2440_spi_channel {
+	volatile unsigned char	SPCON;
+	volatile unsigned char	res1[3];
+	volatile unsigned char	SPSTA;
+	volatile unsigned char	res2[3];
+	volatile unsigned char	SPPIN;
+	volatile unsigned char	res3[3];
+	volatile unsigned char	SPPRE;
+	volatile unsigned char	res4[3];
+	volatile unsigned char	SPTDAT;
+	volatile unsigned char	res5[3];
+	volatile unsigned char	SPRDAT;
+	volatile unsigned char	res6[3];
+	volatile unsigned char	res7[16];
+};
+
+struct s3c2440_spi {
+	struct s3c2440_spi_channel	ch[S3C2440_SPI_CHANNELS];
+};
+
+
+struct s3c2440_sdi {
+	volatile unsigned int	SDICON;
+	volatile unsigned int	SDIPRE;
+	volatile unsigned int	SDICARG;
+	volatile unsigned int	SDICCON;
+	volatile unsigned int	SDICSTA;
+	volatile unsigned int	SDIRSP0;
+	volatile unsigned int	SDIRSP1;
+	volatile unsigned int	SDIRSP2;
+	volatile unsigned int	SDIRSP3;
+	volatile unsigned int	SDIDTIMER;
+	volatile unsigned int	SDIBSIZE;
+	volatile unsigned int	SDIDCON;
+	volatile unsigned int	SDIDCNT;
+	volatile unsigned int	SDIDSTA;
+	volatile unsigned int	SDIFSTA;
+#ifdef __BIG_ENDIAN
+	volatile unsigned char	res[3];
+	volatile unsigned char	SDIDAT;
+#else
+	volatile unsigned char	SDIDAT;
+	volatile unsigned char	res[3];
+#endif
+	volatile unsigned int	SDIIMSK;
+};
+
+
+
+/* S3C2440 only supports 512 Byte HW ECC */
+#define S3C2440_ECCSIZE		512
+#define S3C2440_ECCBYTES	3
+
+enum s3c2440_uarts_nr {
+	S3C2440_UART0 = 0,
+	S3C2440_UART1 = 1,
+	S3C2440_UART2 = 2
+};
+
+/* S3C2440 device base addresses */
+#define S3C2440_MEMCTL_BASE			0x48000000
+#define S3C2440_USB_HOST_BASE		0x49000000
+#define S3C2440_INTERRUPT_BASE		0x4A000000
+#define S3C2440_DMA_BASE			0x4B000000
+#define S3C2440_CLOCK_POWER_BASE	0x4C000000
+#define S3C2440_LCD_BASE			0x4D000000
+#define S3C2440_NAND_BASE			0x4E000000
+#define S3C2440_UART_BASE			0x50000000
+#define S3C2440_TIMER_BASE			0x51000000
+#define S3C2440_USB_DEVICE_BASE		0x52000140
+#define S3C2440_WATCHDOG_BASE		0x53000000
+#define S3C2440_I2C_BASE			0x54000000
+#define S3C2440_I2S_BASE			0x55000000
+#define S3C2440_GPIO_BASE			0x56000000
+#define S3C2440_RTC_BASE			0x57000000
+#define S3C2440_ADC_BASE			0x58000000
+#define S3C2440_SPI_BASE			0x59000000
+#define S3C2440_SDI_BASE			0x5A000000
+
+
+static inline struct s3c2440_memctl *s3c2440_get_base_memctl(void)
+{
+	return (struct s3c2440_memctl *)S3C2440_MEMCTL_BASE;
+}
+
+static inline struct s3c2440_usb_host *s3c2440_get_base_usb_host(void)
+{
+	return (struct s3c2440_usb_host *)S3C2440_USB_HOST_BASE;
+}
+
+static inline struct s3c2440_interrupt *s3c2440_get_base_interrupt(void)
+{
+	return (struct s3c2440_interrupt *)S3C2440_INTERRUPT_BASE;
+}
+
+static inline struct s3c2440_dmas *s3c2440_get_base_dmas(void)
+{
+	return (struct s3c2440_dmas *)S3C2440_DMA_BASE;
+}
+
+static inline struct s3c2440_clock_power *s3c2440_get_base_clock_power(void)
+{
+	return (struct s3c2440_clock_power *)S3C2440_CLOCK_POWER_BASE;
+}
+
+static inline struct s3c2440_lcd *s3c2440_get_base_lcd(void)
+{
+	return (struct s3c2440_lcd *)S3C2440_LCD_BASE;
+}
+
+static inline struct s3c2440_nand *s3c2440_get_base_nand(void)
+{
+	return (struct s3c2440_nand *)S3C2440_NAND_BASE;
+}
+
+static inline struct s3c2440_uart *s3c2440_get_base_uart(enum s3c2440_uarts_nr n)
+{
+	return (struct s3c2440_uart *)(S3C2440_UART_BASE + (n * 0x4000));
+}
+
+static inline struct s3c2440_timers *s3c2440_get_base_timers(void)
+{
+	return (struct s3c2440_timers *)S3C2440_TIMER_BASE;
+}
+
+static inline struct s3c2440_usb_device *s3c2440_get_base_usb_device(void)
+{
+	return (struct s3c2440_usb_device *)S3C2440_USB_DEVICE_BASE;
+}
+
+static inline struct s3c2440_watchdog *s3c2440_get_base_watchdog(void)
+{
+	return (struct s3c2440_watchdog *)S3C2440_WATCHDOG_BASE;
+}
+
+static inline struct s3c2440_i2c *s3c2440_get_base_i2c(void)
+{
+	return (struct s3c2440_i2c *)S3C2440_I2C_BASE;
+}
+
+static inline struct s3c2440_i2s *s3c2440_get_base_i2s(void)
+{
+	return (struct s3c2440_i2s *)S3C2440_I2S_BASE;
+}
+
+static inline struct s3c2440_gpio *s3c2440_get_base_gpio(void)
+{
+	return (struct s3c2440_gpio *)S3C2440_GPIO_BASE;
+}
+
+static inline struct s3c2440_rtc *s3c2440_get_base_rtc(void)
+{
+	return (struct s3c2440_rtc *)S3C2440_RTC_BASE;
+}
+
+static inline struct s3c2440_adc *s3c2440_get_base_adc(void)
+{
+	return (struct s3c2440_adc *)S3C2440_ADC_BASE;
+}
+
+static inline struct s3c2440_spi *s3c2440_get_base_spi(void)
+{
+	return (struct s3c2440_spi *)S3C2440_SPI_BASE;
+}
+
+static inline struct s3c2440_sdi *s3c2440_get_base_sdi(void)
+{
+	return (struct s3c2440_sdi *)S3C2440_SDI_BASE;
+}
+
+#endif /*__S3C2440_H__*/
diff --git a/linux-bsp/asm-study/yaffs2/bsp/s3c_board.c b/linux-bsp/asm-study/yaffs2/bsp/s3c_board.c
new file mode 100644
index 0000000..8007477
--- /dev/null
+++ b/linux-bsp/asm-study/yaffs2/bsp/s3c_board.c
@@ -0,0 +1,213 @@
+#include "s3c_board.h"
+#include "s3c2440.h"
+
+unsigned int s3c2440_get_fclk(void)
+{ 
+    struct s3c2440_clock_power *clk_power = s3c2440_get_base_clock_power();
+	unsigned int r, m, p, s;
+
+	r = clk_power->MPLLCON;
+
+	m = ((r & 0xFF000) >> 12) + 8;
+    p = ((r & 0x003F0) >> 4) + 2;
+    s = r & 0x3;
+
+	return (SYS_CLK_FREQ * m * 2) / (p << s);
+}
+ 
+unsigned int s3c2440_get_hclk(void)
+{
+    struct s3c2440_clock_power * const clk_power = s3c2440_get_base_clock_power();
+	unsigned int fclk = s3c2440_get_fclk();
+
+	if (clk_power->CLKDIVN & 0x6)
+	{
+		if ((clk_power->CLKDIVN & 0x6)==2)
+			return fclk/2;
+		if ((clk_power->CLKDIVN & 0x6)==6)
+			return (clk_power->CAMDIVN & 0x100) ? fclk/6 : fclk/3;
+		if ((clk_power->CLKDIVN & 0x6)==4)
+			return (clk_power->CAMDIVN & 0x200) ? fclk/8 : fclk/4;
+		return fclk;
+	}
+
+	return fclk;
+}
+ 
+unsigned int s3c2440_get_pclk(void)
+{
+    struct s3c2440_clock_power * const clk_power = s3c2440_get_base_clock_power();
+	unsigned int hclk = s3c2440_get_hclk();
+
+    return (clk_power->CLKDIVN & 0x1) ? hclk/2 : hclk;
+}
+ 
+unsigned int s3c2440_get_uclk(void)
+{
+    struct s3c2440_clock_power *clk_power = s3c2440_get_base_clock_power();
+	unsigned int r, m, p, s;
+
+	r = clk_power->UPLLCON;
+
+	m = ((r & 0xFF000) >> 12) + 8;
+    p = ((r & 0x003F0) >> 4) + 2;
+    s = r & 0x3;
+
+	return (SYS_CLK_FREQ * m) / (p << s);
+}
+
+void s3c2440_set_baudrate(unsigned int baudrate, int index)
+{
+	struct s3c2440_uart *uart = s3c2440_get_base_uart(index);
+	unsigned int reg = 0;
+	int i; 
+	reg = s3c2440_get_pclk() / (16 * baudrate) - 1;
+
+	uart->UBRDIV = reg;
+	for (i = 0; i < 100; i++);
+} 
+ 
+int s3c2440_serial_init(unsigned int baudrate, int index)
+{
+	struct s3c2440_uart *uart = s3c2440_get_base_uart(index);
+
+	/* FIFO enable, Tx/Rx FIFO clear */
+	uart->UFCON = 0x07;
+	uart->UMCON = 0x0;
+
+	/* Normal,No parity,1 stop,8 bit */
+	uart->ULCON = 0x3;
+	/*
+	 * tx=level,rx=edge,disable timeout int.,enable rx error int.,
+	 * normal,interrupt or polling
+	 */
+	uart->UCON = (1<<8) | (1<<2) | (1<<0);
+
+//	uart->UMCON = 0x1; /* RTS up */
+ 
+	s3c2440_set_baudrate(baudrate, index);
+
+	return (0);
+}
+
+int s3c2440_serail_set_afc(int enable, int index)
+{
+	if (index != S3C2440_UART0 || index != S3C2440_UART1)
+		return -1;
+
+	struct s3c2440_uart *uart = s3c2440_get_base_uart(index);
+	if (enable) {
+		uart->UMCON = (1<<4);
+	} else {
+		uart->UMCON = 0;
+		uart->UMCON = 0;
+		uart->UMCON = 0;
+		uart->UMCON = 1;
+	}
+
+	return 0;
+}
+
+/*
+ * Read a single byte from the serial port. Returns 1 on success, 0
+ * otherwise. When the function is succesfull, the character read is
+ * written into its argument c.
+ */
+int s3c2440_serial_getc (int index)
+{
+	struct s3c2440_uart *uart = s3c2440_get_base_uart(index);
+
+	/* wait for character to arrive */
+	//while (!(uart->UTRSTAT & 0x1));
+	while(!(uart->UFSTAT & 0x1F));
+
+	return uart->URXH & 0xff;
+} 
+
+#if 0
+static int hwflow = 0; /* turned off by default */
+int hwflow_onoff(int on)
+{
+	switch(on) {
+	case 0:
+	default:
+		break; /* return current */
+	case 1:
+		hwflow = 1; /* turn on */
+		break;
+	case -1:
+		hwflow = 0; /* turn off */
+		break;
+	}
+	return hwflow;
+}
+#endif
+
+#if 0 
+static int be_quiet = 0;
+void disable_putc(void)
+{
+	be_quiet = 1;
+}
+
+void enable_putc(void)
+{
+	be_quiet = 0;
+}
+#endif
+
+
+/*
+ * Output a single byte to the serial port.
+ */
+void s3c2440_serial_putc (char c, int index)
+{
+	struct s3c2440_uart *uart = s3c2440_get_base_uart(index);
+
+	/* wait for room in the tx FIFO */
+	//while ((!(uart->UTRSTAT & 0x2)));
+	while (uart->UFSTAT & (1<<14));
+	uart->UTXH = c;
+}
+
+
+void s3c2440_serial_puts(const char *s, int index)
+{
+	while (*s) 
+    {
+        if (*s == '\n')              /*  If \n, also do \r */
+            s3c2440_serial_putc('\r', index);
+		s3c2440_serial_putc (*s++, index);
+	}
+}
+
+
+void s3c2440_interrupt_enable(unsigned int mask)
+{
+	mask = ~mask;
+	struct s3c2440_interrupt *interrupt = s3c2440_get_base_interrupt();
+	interrupt->INTMSK &= mask;
+}
+
+void s3c2440_interrupt_disable(unsigned int mask)
+{
+	struct s3c2440_interrupt *interrupt = s3c2440_get_base_interrupt();
+	interrupt->INTMSK |= mask;
+}
+
+void s3c2440_sub_interrupt_enable(unsigned int mask)
+{
+	mask = ~mask;
+	struct s3c2440_interrupt *interrupt = s3c2440_get_base_interrupt();
+	interrupt->INTSUBMSK &= mask;
+}
+
+void s3c2440_sub_interrupt_disable(unsigned int mask)
+{
+	struct s3c2440_interrupt *interrupt = s3c2440_get_base_interrupt();
+	interrupt->INTSUBMSK |= mask;
+}
+
+
+
+ 
diff --git a/linux-bsp/asm-study/yaffs2/bsp/s3c_board.h b/linux-bsp/asm-study/yaffs2/bsp/s3c_board.h
new file mode 100644
index 0000000..7b979a1
--- /dev/null
+++ b/linux-bsp/asm-study/yaffs2/bsp/s3c_board.h
@@ -0,0 +1,34 @@
+#ifndef __S3C_BOARD_H__
+#define __S3C_BOARD_H__
+
+#include "s3c2440.h"
+
+#define SYS_CLK_FREQ             12000000 
+#define CONSOLE_SERIAL           S3C2440_UART0
+#define CONSOLE_BAUDRATE         115200
+
+unsigned int s3c2440_get_fclk(void);
+unsigned int s3c2440_get_hclk(void);
+unsigned int s3c2440_get_pclk(void);
+unsigned int s3c2440_get_uclk(void);
+
+void s3c2440_set_baudrate(unsigned int baudrate, int index);
+int s3c2440_serial_init(unsigned int baudrate, int index);
+int s3c2440_serail_set_afc(int enable, int index);
+int s3c2440_serial_getc (int index);
+void s3c2440_serial_putc (char ch, int index);
+int s3c2440_serial_tstc(int index);
+void s3c2440_serial_puts(const char *s, int index);
+
+#define console_serial_init()      s3c2440_serial_init(CONSOLE_BAUDRATE, CONSOLE_SERIAL)
+#define console_serial_getc()      s3c2440_serial_getc(CONSOLE_SERIAL)
+#define console_serial_tstc()      s3c2440_serial_tstc(CONSOLE_SERIAL)
+#define console_serial_putc(c)     s3c2440_serial_putc(c, CONSOLE_SERIAL)
+#define console_serial_puts(s)     s3c2440_serial_puts(s, CONSOLE_SERIAL)
+
+void s3c2440_interrupt_enable(unsigned int mask);
+void s3c2440_interrupt_disable(unsigned int mask);
+void s3c2440_sub_interrupt_enable(unsigned int mask);
+void s3c2440_sub_interrupt_disable(unsigned int mask);
+
+#endif
diff --git a/linux-bsp/asm-study/yaffs2/common/dlmalloc.c b/linux-bsp/asm-study/yaffs2/common/dlmalloc.c
new file mode 100644
index 0000000..8ba1694
--- /dev/null
+++ b/linux-bsp/asm-study/yaffs2/common/dlmalloc.c
@@ -0,0 +1,3320 @@
+#include <stdio.h>
+#include <string.h>
+#include <malloc.h>
+
+#define DEBUG   1
+
+#if 0	/* Moved to malloc.h */
+/* ---------- To make a malloc.h, start cutting here ------------ */
+
+/*
+  A version of malloc/free/realloc written by Doug Lea and released to the
+  public domain.  Send questions/comments/complaints/performance data
+  to dl@cs.oswego.edu
+
+* VERSION 2.6.6  Sun Mar  5 19:10:03 2000  Doug Lea  (dl at gee)
+
+   Note: There may be an updated version of this malloc obtainable at
+	   ftp://g.oswego.edu/pub/misc/malloc.c
+	 Check before installing!
+
+* Why use this malloc?
+
+  This is not the fastest, most space-conserving, most portable, or
+  most tunable malloc ever written. However it is among the fastest
+  while also being among the most space-conserving, portable and tunable.
+  Consistent balance across these factors results in a good general-purpose
+  allocator. For a high-level description, see
+     http://g.oswego.edu/dl/html/malloc.html
+
+* Synopsis of public routines
+
+  (Much fuller descriptions are contained in the program documentation below.)
+
+  malloc(size_t n);
+     Return a pointer to a newly allocated chunk of at least n bytes, or null
+     if no space is available.
+  free(Void_t* p);
+     Release the chunk of memory pointed to by p, or no effect if p is null.
+  realloc(Void_t* p, size_t n);
+     Return a pointer to a chunk of size n that contains the same data
+     as does chunk p up to the minimum of (n, p's size) bytes, or null
+     if no space is available. The returned pointer may or may not be
+     the same as p. If p is null, equivalent to malloc.  Unless the
+     #define REALLOC_ZERO_BYTES_FREES below is set, realloc with a
+     size argument of zero (re)allocates a minimum-sized chunk.
+  memalign(size_t alignment, size_t n);
+     Return a pointer to a newly allocated chunk of n bytes, aligned
+     in accord with the alignment argument, which must be a power of
+     two.
+  valloc(size_t n);
+     Equivalent to memalign(pagesize, n), where pagesize is the page
+     size of the system (or as near to this as can be figured out from
+     all the includes/defines below.)
+  pvalloc(size_t n);
+     Equivalent to valloc(minimum-page-that-holds(n)), that is,
+     round up n to nearest pagesize.
+  calloc(size_t unit, size_t quantity);
+     Returns a pointer to quantity * unit bytes, with all locations
+     set to zero.
+  cfree(Void_t* p);
+     Equivalent to free(p).
+  malloc_trim(size_t pad);
+     Release all but pad bytes of freed top-most memory back
+     to the system. Return 1 if successful, else 0.
+  malloc_usable_size(Void_t* p);
+     Report the number usable allocated bytes associated with allocated
+     chunk p. This may or may not report more bytes than were requested,
+     due to alignment and minimum size constraints.
+  malloc_stats();
+     Prints brief summary statistics.
+  mallinfo()
+     Returns (by copy) a struct containing various summary statistics.
+  mallopt(int parameter_number, int parameter_value)
+     Changes one of the tunable parameters described below. Returns
+     1 if successful in changing the parameter, else 0.
+
+* Vital statistics:
+
+  Alignment:                            8-byte
+       8 byte alignment is currently hardwired into the design.  This
+       seems to suffice for all current machines and C compilers.
+
+  Assumed pointer representation:       4 or 8 bytes
+       Code for 8-byte pointers is untested by me but has worked
+       reliably by Wolfram Gloger, who contributed most of the
+       changes supporting this.
+
+  Assumed size_t  representation:       4 or 8 bytes
+       Note that size_t is allowed to be 4 bytes even if pointers are 8.
+
+  Minimum overhead per allocated chunk: 4 or 8 bytes
+       Each malloced chunk has a hidden overhead of 4 bytes holding size
+       and status information.
+
+  Minimum allocated size: 4-byte ptrs:  16 bytes    (including 4 overhead)
+			  8-byte ptrs:  24/32 bytes (including, 4/8 overhead)
+
+       When a chunk is freed, 12 (for 4byte ptrs) or 20 (for 8 byte
+       ptrs but 4 byte size) or 24 (for 8/8) additional bytes are
+       needed; 4 (8) for a trailing size field
+       and 8 (16) bytes for free list pointers. Thus, the minimum
+       allocatable size is 16/24/32 bytes.
+
+       Even a request for zero bytes (i.e., malloc(0)) returns a
+       pointer to something of the minimum allocatable size.
+
+  Maximum allocated size: 4-byte size_t: 2^31 -  8 bytes
+			  8-byte size_t: 2^63 - 16 bytes
+
+       It is assumed that (possibly signed) size_t bit values suffice to
+       represent chunk sizes. `Possibly signed' is due to the fact
+       that `size_t' may be defined on a system as either a signed or
+       an unsigned type. To be conservative, values that would appear
+       as negative numbers are avoided.
+       Requests for sizes with a negative sign bit when the request
+       size is treaded as a long will return null.
+
+  Maximum overhead wastage per allocated chunk: normally 15 bytes
+
+       Alignnment demands, plus the minimum allocatable size restriction
+       make the normal worst-case wastage 15 bytes (i.e., up to 15
+       more bytes will be allocated than were requested in malloc), with
+       two exceptions:
+	 1. Because requests for zero bytes allocate non-zero space,
+	    the worst case wastage for a request of zero bytes is 24 bytes.
+	 2. For requests >= mmap_threshold that are serviced via
+	    mmap(), the worst case wastage is 8 bytes plus the remainder
+	    from a system page (the minimal mmap unit); typically 4096 bytes.
+
+* Limitations
+
+    Here are some features that are NOT currently supported
+
+    * No user-definable hooks for callbacks and the like.
+    * No automated mechanism for fully checking that all accesses
+      to malloced memory stay within their bounds.
+    * No support for compaction.
+
+* Synopsis of compile-time options:
+
+    People have reported using previous versions of this malloc on all
+    versions of Unix, sometimes by tweaking some of the defines
+    below. It has been tested most extensively on Solaris and
+    Linux. It is also reported to work on WIN32 platforms.
+    People have also reported adapting this malloc for use in
+    stand-alone embedded systems.
+
+    The implementation is in straight, hand-tuned ANSI C.  Among other
+    consequences, it uses a lot of macros.  Because of this, to be at
+    all usable, this code should be compiled using an optimizing compiler
+    (for example gcc -O2) that can simplify expressions and control
+    paths.
+
+  __STD_C                  (default: derived from C compiler defines)
+     Nonzero if using ANSI-standard C compiler, a C++ compiler, or
+     a C compiler sufficiently close to ANSI to get away with it.
+  DEBUG                    (default: NOT defined)
+     Define to enable debugging. Adds fairly extensive assertion-based
+     checking to help track down memory errors, but noticeably slows down
+     execution.
+  REALLOC_ZERO_BYTES_FREES (default: NOT defined)
+     Define this if you think that realloc(p, 0) should be equivalent
+     to free(p). Otherwise, since malloc returns a unique pointer for
+     malloc(0), so does realloc(p, 0).
+  HAVE_MEMCPY               (default: defined)
+     Define if you are not otherwise using ANSI STD C, but still
+     have memcpy and memset in your C library and want to use them.
+     Otherwise, simple internal versions are supplied.
+  USE_MEMCPY               (default: 1 if HAVE_MEMCPY is defined, 0 otherwise)
+     Define as 1 if you want the C library versions of memset and
+     memcpy called in realloc and calloc (otherwise macro versions are used).
+     At least on some platforms, the simple macro versions usually
+     outperform libc versions.
+  HAVE_MMAP                 (default: defined as 1)
+     Define to non-zero to optionally make malloc() use mmap() to
+     allocate very large blocks.
+  HAVE_MREMAP                 (default: defined as 0 unless Linux libc set)
+     Define to non-zero to optionally make realloc() use mremap() to
+     reallocate very large blocks.
+  malloc_getpagesize        (default: derived from system #includes)
+     Either a constant or routine call returning the system page size.
+  HAVE_USR_INCLUDE_MALLOC_H (default: NOT defined)
+     Optionally define if you are on a system with a /usr/include/malloc.h
+     that declares struct mallinfo. It is not at all necessary to
+     define this even if you do, but will ensure consistency.
+  INTERNAL_SIZE_T           (default: size_t)
+     Define to a 32-bit type (probably `unsigned int') if you are on a
+     64-bit machine, yet do not want or need to allow malloc requests of
+     greater than 2^31 to be handled. This saves space, especially for
+     very small chunks.
+  INTERNAL_LINUX_C_LIB      (default: NOT defined)
+     Defined only when compiled as part of Linux libc.
+     Also note that there is some odd internal name-mangling via defines
+     (for example, internally, `malloc' is named `mALLOc') needed
+     when compiling in this case. These look funny but don't otherwise
+     affect anything.
+  WIN32                     (default: undefined)
+     Define this on MS win (95, nt) platforms to compile in sbrk emulation.
+  LACKS_UNISTD_H            (default: undefined if not WIN32)
+     Define this if your system does not have a <unistd.h>.
+  LACKS_SYS_PARAM_H         (default: undefined if not WIN32)
+     Define this if your system does not have a <sys/param.h>.
+  MORECORE                  (default: sbrk)
+     The name of the routine to call to obtain more memory from the system.
+  MORECORE_FAILURE          (default: -1)
+     The value returned upon failure of MORECORE.
+  MORECORE_CLEARS           (default 1)
+     true (1) if the routine mapped to MORECORE zeroes out memory (which
+     holds for sbrk).
+  DEFAULT_TRIM_THRESHOLD
+  DEFAULT_TOP_PAD
+  DEFAULT_MMAP_THRESHOLD
+  DEFAULT_MMAP_MAX
+     Default values of tunable parameters (described in detail below)
+     controlling interaction with host system routines (sbrk, mmap, etc).
+     These values may also be changed dynamically via mallopt(). The
+     preset defaults are those that give best performance for typical
+     programs/systems.
+  USE_DL_PREFIX             (default: undefined)
+     Prefix all public routines with the string 'dl'.  Useful to
+     quickly avoid procedure declaration conflicts and linker symbol
+     conflicts with existing memory allocation routines.
+
+
+*/
+
+
+
+/* Preliminaries */
+
+#ifndef __STD_C
+#ifdef __STDC__
+#define __STD_C     1
+#else
+#if __cplusplus
+#define __STD_C     1
+#else
+#define __STD_C     0
+#endif /*__cplusplus*/
+#endif /*__STDC__*/
+#endif /*__STD_C*/
+
+#ifndef Void_t
+#if (__STD_C || defined(WIN32))
+#define Void_t      void
+#else
+#define Void_t      char
+#endif
+#endif /*Void_t*/
+
+#if __STD_C
+#include <stddef.h>   /* for size_t */
+#else
+#include <sys/types.h>
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <stdio.h>    /* needed for malloc_stats */
+
+
+/*
+  Compile-time options
+*/
+
+
+/*
+    Debugging:
+
+    Because freed chunks may be overwritten with link fields, this
+    malloc will often die when freed memory is overwritten by user
+    programs.  This can be very effective (albeit in an annoying way)
+    in helping track down dangling pointers.
+
+    If you compile with -DDEBUG, a number of assertion checks are
+    enabled that will catch more memory errors. You probably won't be
+    able to make much sense of the actual assertion errors, but they
+    should help you locate incorrectly overwritten memory.  The
+    checking is fairly extensive, and will slow down execution
+    noticeably. Calling malloc_stats or mallinfo with DEBUG set will
+    attempt to check every non-mmapped allocated and free chunk in the
+    course of computing the summmaries. (By nature, mmapped regions
+    cannot be checked very much automatically.)
+
+    Setting DEBUG may also be helpful if you are trying to modify
+    this code. The assertions in the check routines spell out in more
+    detail the assumptions and invariants underlying the algorithms.
+
+*/
+
+/*
+  INTERNAL_SIZE_T is the word-size used for internal bookkeeping
+  of chunk sizes. On a 64-bit machine, you can reduce malloc
+  overhead by defining INTERNAL_SIZE_T to be a 32 bit `unsigned int'
+  at the expense of not being able to handle requests greater than
+  2^31. This limitation is hardly ever a concern; you are encouraged
+  to set this. However, the default version is the same as size_t.
+*/
+
+#ifndef INTERNAL_SIZE_T
+#define INTERNAL_SIZE_T size_t
+#endif
+
+/*
+  REALLOC_ZERO_BYTES_FREES should be set if a call to
+  realloc with zero bytes should be the same as a call to free.
+  Some people think it should. Otherwise, since this malloc
+  returns a unique pointer for malloc(0), so does realloc(p, 0).
+*/
+
+
+/*   #define REALLOC_ZERO_BYTES_FREES */
+
+
+/*
+  WIN32 causes an emulation of sbrk to be compiled in
+  mmap-based options are not currently supported in WIN32.
+*/
+
+/* #define WIN32 */
+#ifdef WIN32
+#define MORECORE wsbrk
+#define HAVE_MMAP 0
+
+#define LACKS_UNISTD_H
+#define LACKS_SYS_PARAM_H
+
+/*
+  Include 'windows.h' to get the necessary declarations for the
+  Microsoft Visual C++ data structures and routines used in the 'sbrk'
+  emulation.
+
+  Define WIN32_LEAN_AND_MEAN so that only the essential Microsoft
+  Visual C++ header files are included.
+*/
+#define WIN32_LEAN_AND_MEAN
+#include <windows.h>
+#endif
+
+
+/*
+  HAVE_MEMCPY should be defined if you are not otherwise using
+  ANSI STD C, but still have memcpy and memset in your C library
+  and want to use them in calloc and realloc. Otherwise simple
+  macro versions are defined here.
+
+  USE_MEMCPY should be defined as 1 if you actually want to
+  have memset and memcpy called. People report that the macro
+  versions are often enough faster than libc versions on many
+  systems that it is better to use them.
+
+*/
+
+#define HAVE_MEMCPY
+
+#ifndef USE_MEMCPY
+#ifdef HAVE_MEMCPY
+#define USE_MEMCPY 1
+#else
+#define USE_MEMCPY 0
+#endif
+#endif
+
+#if (__STD_C || defined(HAVE_MEMCPY))
+
+#if __STD_C
+void* memset(void*, int, size_t);
+void* memcpy(void*, const void*, size_t);
+#else
+#ifdef WIN32
+/* On Win32 platforms, 'memset()' and 'memcpy()' are already declared in */
+/* 'windows.h' */
+#else
+Void_t* memset();
+Void_t* memcpy();
+#endif
+#endif
+#endif
+
+#if USE_MEMCPY
+
+/* The following macros are only invoked with (2n+1)-multiples of
+   INTERNAL_SIZE_T units, with a positive integer n. This is exploited
+   for fast inline execution when n is small. */
+
+#define MALLOC_ZERO(charp, nbytes)                                            \
+do {                                                                          \
+  INTERNAL_SIZE_T mzsz = (nbytes);                                            \
+  if(mzsz <= 9*sizeof(mzsz)) {                                                \
+    INTERNAL_SIZE_T* mz = (INTERNAL_SIZE_T*) (charp);                         \
+    if(mzsz >= 5*sizeof(mzsz)) {     *mz++ = 0;                               \
+				     *mz++ = 0;                               \
+      if(mzsz >= 7*sizeof(mzsz)) {   *mz++ = 0;                               \
+				     *mz++ = 0;                               \
+	if(mzsz >= 9*sizeof(mzsz)) { *mz++ = 0;                               \
+				     *mz++ = 0; }}}                           \
+				     *mz++ = 0;                               \
+				     *mz++ = 0;                               \
+				     *mz   = 0;                               \
+  } else memset((charp), 0, mzsz);                                            \
+} while(0)
+
+#define MALLOC_COPY(dest,src,nbytes)                                          \
+do {                                                                          \
+  INTERNAL_SIZE_T mcsz = (nbytes);                                            \
+  if(mcsz <= 9*sizeof(mcsz)) {                                                \
+    INTERNAL_SIZE_T* mcsrc = (INTERNAL_SIZE_T*) (src);                        \
+    INTERNAL_SIZE_T* mcdst = (INTERNAL_SIZE_T*) (dest);                       \
+    if(mcsz >= 5*sizeof(mcsz)) {     *mcdst++ = *mcsrc++;                     \
+				     *mcdst++ = *mcsrc++;                     \
+      if(mcsz >= 7*sizeof(mcsz)) {   *mcdst++ = *mcsrc++;                     \
+				     *mcdst++ = *mcsrc++;                     \
+	if(mcsz >= 9*sizeof(mcsz)) { *mcdst++ = *mcsrc++;                     \
+				     *mcdst++ = *mcsrc++; }}}                 \
+				     *mcdst++ = *mcsrc++;                     \
+				     *mcdst++ = *mcsrc++;                     \
+				     *mcdst   = *mcsrc  ;                     \
+  } else memcpy(dest, src, mcsz);                                             \
+} while(0)
+
+#else /* !USE_MEMCPY */
+
+/* Use Duff's device for good zeroing/copying performance. */
+
+#define MALLOC_ZERO(charp, nbytes)                                            \
+do {                                                                          \
+  INTERNAL_SIZE_T* mzp = (INTERNAL_SIZE_T*)(charp);                           \
+  long mctmp = (nbytes)/sizeof(INTERNAL_SIZE_T), mcn;                         \
+  if (mctmp < 8) mcn = 0; else { mcn = (mctmp-1)/8; mctmp %= 8; }             \
+  switch (mctmp) {                                                            \
+    case 0: for(;;) { *mzp++ = 0;                                             \
+    case 7:           *mzp++ = 0;                                             \
+    case 6:           *mzp++ = 0;                                             \
+    case 5:           *mzp++ = 0;                                             \
+    case 4:           *mzp++ = 0;                                             \
+    case 3:           *mzp++ = 0;                                             \
+    case 2:           *mzp++ = 0;                                             \
+    case 1:           *mzp++ = 0; if(mcn <= 0) break; mcn--; }                \
+  }                                                                           \
+} while(0)
+
+#define MALLOC_COPY(dest,src,nbytes)                                          \
+do {                                                                          \
+  INTERNAL_SIZE_T* mcsrc = (INTERNAL_SIZE_T*) src;                            \
+  INTERNAL_SIZE_T* mcdst = (INTERNAL_SIZE_T*) dest;                           \
+  long mctmp = (nbytes)/sizeof(INTERNAL_SIZE_T), mcn;                         \
+  if (mctmp < 8) mcn = 0; else { mcn = (mctmp-1)/8; mctmp %= 8; }             \
+  switch (mctmp) {                                                            \
+    case 0: for(;;) { *mcdst++ = *mcsrc++;                                    \
+    case 7:           *mcdst++ = *mcsrc++;                                    \
+    case 6:           *mcdst++ = *mcsrc++;                                    \
+    case 5:           *mcdst++ = *mcsrc++;                                    \
+    case 4:           *mcdst++ = *mcsrc++;                                    \
+    case 3:           *mcdst++ = *mcsrc++;                                    \
+    case 2:           *mcdst++ = *mcsrc++;                                    \
+    case 1:           *mcdst++ = *mcsrc++; if(mcn <= 0) break; mcn--; }       \
+  }                                                                           \
+} while(0)
+
+#endif
+
+
+/*
+  Define HAVE_MMAP to optionally make malloc() use mmap() to
+  allocate very large blocks.  These will be returned to the
+  operating system immediately after a free().
+*/
+
+#ifndef HAVE_MMAP
+#define HAVE_MMAP 1
+#endif
+
+/*
+  Define HAVE_MREMAP to make realloc() use mremap() to re-allocate
+  large blocks.  This is currently only possible on Linux with
+  kernel versions newer than 1.3.77.
+*/
+
+#ifndef HAVE_MREMAP
+#ifdef INTERNAL_LINUX_C_LIB
+#define HAVE_MREMAP 1
+#else
+#define HAVE_MREMAP 0
+#endif
+#endif
+
+#if HAVE_MMAP
+
+#include <unistd.h>
+#include <fcntl.h>
+#include <sys/mman.h>
+
+#if !defined(MAP_ANONYMOUS) && defined(MAP_ANON)
+#define MAP_ANONYMOUS MAP_ANON
+#endif
+
+#endif /* HAVE_MMAP */
+
+/*
+  Access to system page size. To the extent possible, this malloc
+  manages memory from the system in page-size units.
+
+  The following mechanics for getpagesize were adapted from
+  bsd/gnu getpagesize.h
+*/
+
+#ifndef LACKS_UNISTD_H
+#  include <unistd.h>
+#endif
+
+#ifndef malloc_getpagesize
+#  ifdef _SC_PAGESIZE         /* some SVR4 systems omit an underscore */
+#    ifndef _SC_PAGE_SIZE
+#      define _SC_PAGE_SIZE _SC_PAGESIZE
+#    endif
+#  endif
+#  ifdef _SC_PAGE_SIZE
+#    define malloc_getpagesize sysconf(_SC_PAGE_SIZE)
+#  else
+#    if defined(BSD) || defined(DGUX) || defined(HAVE_GETPAGESIZE)
+       extern size_t getpagesize();
+#      define malloc_getpagesize getpagesize()
+#    else
+#      ifdef WIN32
+#        define malloc_getpagesize (4096) /* TBD: Use 'GetSystemInfo' instead */
+#      else
+#        ifndef LACKS_SYS_PARAM_H
+#          include <sys/param.h>
+#        endif
+#        ifdef EXEC_PAGESIZE
+#          define malloc_getpagesize EXEC_PAGESIZE
+#        else
+#          ifdef NBPG
+#            ifndef CLSIZE
+#              define malloc_getpagesize NBPG
+#            else
+#              define malloc_getpagesize (NBPG * CLSIZE)
+#            endif
+#          else
+#            ifdef NBPC
+#              define malloc_getpagesize NBPC
+#            else
+#              ifdef PAGESIZE
+#                define malloc_getpagesize PAGESIZE
+#              else
+#                define malloc_getpagesize (4096) /* just guess */
+#              endif
+#            endif
+#          endif
+#        endif
+#      endif
+#    endif
+#  endif
+#endif
+
+
+/*
+
+  This version of malloc supports the standard SVID/XPG mallinfo
+  routine that returns a struct containing the same kind of
+  information you can get from malloc_stats. It should work on
+  any SVID/XPG compliant system that has a /usr/include/malloc.h
+  defining struct mallinfo. (If you'd like to install such a thing
+  yourself, cut out the preliminary declarations as described above
+  and below and save them in a malloc.h file. But there's no
+  compelling reason to bother to do this.)
+
+  The main declaration needed is the mallinfo struct that is returned
+  (by-copy) by mallinfo().  The SVID/XPG malloinfo struct contains a
+  bunch of fields, most of which are not even meaningful in this
+  version of malloc. Some of these fields are are instead filled by
+  mallinfo() with other numbers that might possibly be of interest.
+
+  HAVE_USR_INCLUDE_MALLOC_H should be set if you have a
+  /usr/include/malloc.h file that includes a declaration of struct
+  mallinfo.  If so, it is included; else an SVID2/XPG2 compliant
+  version is declared below.  These must be precisely the same for
+  mallinfo() to work.
+
+*/
+
+/* #define HAVE_USR_INCLUDE_MALLOC_H */
+
+#if HAVE_USR_INCLUDE_MALLOC_H
+#include "/usr/include/malloc.h"
+#else
+
+/* SVID2/XPG mallinfo structure */
+
+struct mallinfo {
+  int arena;    /* total space allocated from system */
+  int ordblks;  /* number of non-inuse chunks */
+  int smblks;   /* unused -- always zero */
+  int hblks;    /* number of mmapped regions */
+  int hblkhd;   /* total space in mmapped regions */
+  int usmblks;  /* unused -- always zero */
+  int fsmblks;  /* unused -- always zero */
+  int uordblks; /* total allocated space */
+  int fordblks; /* total non-inuse space */
+  int keepcost; /* top-most, releasable (via malloc_trim) space */
+};
+
+/* SVID2/XPG mallopt options */
+
+#define M_MXFAST  1    /* UNUSED in this malloc */
+#define M_NLBLKS  2    /* UNUSED in this malloc */
+#define M_GRAIN   3    /* UNUSED in this malloc */
+#define M_KEEP    4    /* UNUSED in this malloc */
+
+#endif
+
+/* mallopt options that actually do something */
+
+#define M_TRIM_THRESHOLD    -1
+#define M_TOP_PAD           -2
+#define M_MMAP_THRESHOLD    -3
+#define M_MMAP_MAX          -4
+
+
+#ifndef DEFAULT_TRIM_THRESHOLD
+#define DEFAULT_TRIM_THRESHOLD (128 * 1024)
+#endif
+
+/*
+    M_TRIM_THRESHOLD is the maximum amount of unused top-most memory
+      to keep before releasing via malloc_trim in free().
+
+      Automatic trimming is mainly useful in long-lived programs.
+      Because trimming via sbrk can be slow on some systems, and can
+      sometimes be wasteful (in cases where programs immediately
+      afterward allocate more large chunks) the value should be high
+      enough so that your overall system performance would improve by
+      releasing.
+
+      The trim threshold and the mmap control parameters (see below)
+      can be traded off with one another. Trimming and mmapping are
+      two different ways of releasing unused memory back to the
+      system. Between these two, it is often possible to keep
+      system-level demands of a long-lived program down to a bare
+      minimum. For example, in one test suite of sessions measuring
+      the XF86 X server on Linux, using a trim threshold of 128K and a
+      mmap threshold of 192K led to near-minimal long term resource
+      consumption.
+
+      If you are using this malloc in a long-lived program, it should
+      pay to experiment with these values.  As a rough guide, you
+      might set to a value close to the average size of a process
+      (program) running on your system.  Releasing this much memory
+      would allow such a process to run in memory.  Generally, it's
+      worth it to tune for trimming rather tham memory mapping when a
+      program undergoes phases where several large chunks are
+      allocated and released in ways that can reuse each other's
+      storage, perhaps mixed with phases where there are no such
+      chunks at all.  And in well-behaved long-lived programs,
+      controlling release of large blocks via trimming versus mapping
+      is usually faster.
+
+      However, in most programs, these parameters serve mainly as
+      protection against the system-level effects of carrying around
+      massive amounts of unneeded memory. Since frequent calls to
+      sbrk, mmap, and munmap otherwise degrade performance, the default
+      parameters are set to relatively high values that serve only as
+      safeguards.
+
+      The default trim value is high enough to cause trimming only in
+      fairly extreme (by current memory consumption standards) cases.
+      It must be greater than page size to have any useful effect.  To
+      disable trimming completely, you can set to (unsigned long)(-1);
+
+
+*/
+
+
+#ifndef DEFAULT_TOP_PAD
+#define DEFAULT_TOP_PAD        (0)
+#endif
+
+/*
+    M_TOP_PAD is the amount of extra `padding' space to allocate or
+      retain whenever sbrk is called. It is used in two ways internally:
+
+      * When sbrk is called to extend the top of the arena to satisfy
+	a new malloc request, this much padding is added to the sbrk
+	request.
+
+      * When malloc_trim is called automatically from free(),
+	it is used as the `pad' argument.
+
+      In both cases, the actual amount of padding is rounded
+      so that the end of the arena is always a system page boundary.
+
+      The main reason for using padding is to avoid calling sbrk so
+      often. Having even a small pad greatly reduces the likelihood
+      that nearly every malloc request during program start-up (or
+      after trimming) will invoke sbrk, which needlessly wastes
+      time.
+
+      Automatic rounding-up to page-size units is normally sufficient
+      to avoid measurable overhead, so the default is 0.  However, in
+      systems where sbrk is relatively slow, it can pay to increase
+      this value, at the expense of carrying around more memory than
+      the program needs.
+
+*/
+
+
+#ifndef DEFAULT_MMAP_THRESHOLD
+#define DEFAULT_MMAP_THRESHOLD (128 * 1024)
+#endif
+
+/*
+
+    M_MMAP_THRESHOLD is the request size threshold for using mmap()
+      to service a request. Requests of at least this size that cannot
+      be allocated using already-existing space will be serviced via mmap.
+      (If enough normal freed space already exists it is used instead.)
+
+      Using mmap segregates relatively large chunks of memory so that
+      they can be individually obtained and released from the host
+      system. A request serviced through mmap is never reused by any
+      other request (at least not directly; the system may just so
+      happen to remap successive requests to the same locations).
+
+      Segregating space in this way has the benefit that mmapped space
+      can ALWAYS be individually released back to the system, which
+      helps keep the system level memory demands of a long-lived
+      program low. Mapped memory can never become `locked' between
+      other chunks, as can happen with normally allocated chunks, which
+      menas that even trimming via malloc_trim would not release them.
+
+      However, it has the disadvantages that:
+
+	 1. The space cannot be reclaimed, consolidated, and then
+	    used to service later requests, as happens with normal chunks.
+	 2. It can lead to more wastage because of mmap page alignment
+	    requirements
+	 3. It causes malloc performance to be more dependent on host
+	    system memory management support routines which may vary in
+	    implementation quality and may impose arbitrary
+	    limitations. Generally, servicing a request via normal
+	    malloc steps is faster than going through a system's mmap.
+
+      All together, these considerations should lead you to use mmap
+      only for relatively large requests.
+
+
+*/
+
+
+#ifndef DEFAULT_MMAP_MAX
+#if HAVE_MMAP
+#define DEFAULT_MMAP_MAX       (64)
+#else
+#define DEFAULT_MMAP_MAX       (0)
+#endif
+#endif
+
+/*
+    M_MMAP_MAX is the maximum number of requests to simultaneously
+      service using mmap. This parameter exists because:
+
+	 1. Some systems have a limited number of internal tables for
+	    use by mmap.
+	 2. In most systems, overreliance on mmap can degrade overall
+	    performance.
+	 3. If a program allocates many large regions, it is probably
+	    better off using normal sbrk-based allocation routines that
+	    can reclaim and reallocate normal heap memory. Using a
+	    small value allows transition into this mode after the
+	    first few allocations.
+
+      Setting to 0 disables all use of mmap.  If HAVE_MMAP is not set,
+      the default value is 0, and attempts to set it to non-zero values
+      in mallopt will fail.
+*/
+
+
+/*
+    USE_DL_PREFIX will prefix all public routines with the string 'dl'.
+      Useful to quickly avoid procedure declaration conflicts and linker
+      symbol conflicts with existing memory allocation routines.
+
+*/
+
+/* #define USE_DL_PREFIX */
+
+
+/*
+
+  Special defines for linux libc
+
+  Except when compiled using these special defines for Linux libc
+  using weak aliases, this malloc is NOT designed to work in
+  multithreaded applications.  No semaphores or other concurrency
+  control are provided to ensure that multiple malloc or free calls
+  don't run at the same time, which could be disasterous. A single
+  semaphore could be used across malloc, realloc, and free (which is
+  essentially the effect of the linux weak alias approach). It would
+  be hard to obtain finer granularity.
+
+*/
+
+
+#ifdef INTERNAL_LINUX_C_LIB
+
+#if __STD_C
+
+Void_t * __default_morecore_init (ptrdiff_t);
+Void_t *(*__morecore)(ptrdiff_t) = __default_morecore_init;
+
+#else
+
+Void_t * __default_morecore_init ();
+Void_t *(*__morecore)() = __default_morecore_init;
+
+#endif
+
+#define MORECORE (*__morecore)
+#define MORECORE_FAILURE 0
+#define MORECORE_CLEARS 1
+
+#else /* INTERNAL_LINUX_C_LIB */
+
+#if __STD_C
+extern Void_t*     sbrk(ptrdiff_t);
+#else
+extern Void_t*     sbrk();
+#endif
+
+#ifndef MORECORE
+#define MORECORE sbrk
+#endif
+
+#ifndef MORECORE_FAILURE
+#define MORECORE_FAILURE -1
+#endif
+
+#ifndef MORECORE_CLEARS
+#define MORECORE_CLEARS 1
+#endif
+
+#endif /* INTERNAL_LINUX_C_LIB */
+
+#if defined(INTERNAL_LINUX_C_LIB) && defined(__ELF__)
+
+#define cALLOc		__libc_calloc
+#define fREe		__libc_free
+#define mALLOc		__libc_malloc
+#define mEMALIGn	__libc_memalign
+#define rEALLOc		__libc_realloc
+#define vALLOc		__libc_valloc
+#define pvALLOc		__libc_pvalloc
+#define mALLINFo	__libc_mallinfo
+#define mALLOPt		__libc_mallopt
+
+#pragma weak calloc = __libc_calloc
+#pragma weak free = __libc_free
+#pragma weak cfree = __libc_free
+#pragma weak malloc = __libc_malloc
+#pragma weak memalign = __libc_memalign
+#pragma weak realloc = __libc_realloc
+#pragma weak valloc = __libc_valloc
+#pragma weak pvalloc = __libc_pvalloc
+#pragma weak mallinfo = __libc_mallinfo
+#pragma weak mallopt = __libc_mallopt
+
+#else
+
+#ifdef USE_DL_PREFIX
+#define cALLOc		dlcalloc
+#define fREe		dlfree
+#define mALLOc		dlmalloc
+#define mEMALIGn	dlmemalign
+#define rEALLOc		dlrealloc
+#define vALLOc		dlvalloc
+#define pvALLOc		dlpvalloc
+#define mALLINFo	dlmallinfo
+#define mALLOPt		dlmallopt
+#else /* USE_DL_PREFIX */
+#define cALLOc		calloc
+#define fREe		free
+#define mALLOc		malloc
+#define mEMALIGn	memalign
+#define rEALLOc		realloc
+#define vALLOc		valloc
+#define pvALLOc		pvalloc
+#define mALLINFo	mallinfo
+#define mALLOPt		mallopt
+#endif /* USE_DL_PREFIX */
+
+#endif
+
+/* Public routines */
+
+#if __STD_C
+
+Void_t* mALLOc(size_t);
+void    fREe(Void_t*);
+Void_t* rEALLOc(Void_t*, size_t);
+Void_t* mEMALIGn(size_t, size_t);
+Void_t* vALLOc(size_t);
+Void_t* pvALLOc(size_t);
+Void_t* cALLOc(size_t, size_t);
+void    cfree(Void_t*);
+int     malloc_trim(size_t);
+size_t  malloc_usable_size(Void_t*);
+void    malloc_stats();
+int     mALLOPt(int, int);
+struct mallinfo mALLINFo(void);
+#else
+Void_t* mALLOc();
+void    fREe();
+Void_t* rEALLOc();
+Void_t* mEMALIGn();
+Void_t* vALLOc();
+Void_t* pvALLOc();
+Void_t* cALLOc();
+void    cfree();
+int     malloc_trim();
+size_t  malloc_usable_size();
+void    malloc_stats();
+int     mALLOPt();
+struct mallinfo mALLINFo();
+#endif
+
+
+#ifdef __cplusplus
+};  /* end of extern "C" */
+#endif
+
+/* ---------- To make a malloc.h, end cutting here ------------ */
+#endif	/* 0 */			/* Moved to malloc.h */
+
+#include <malloc.h>
+#ifdef DEBUG
+#if __STD_C
+static void malloc_update_mallinfo (void);
+void malloc_stats (void);
+#else
+static void malloc_update_mallinfo ();
+void malloc_stats();
+#endif
+#endif	/* DEBUG */
+
+/*
+  Emulation of sbrk for WIN32
+  All code within the ifdef WIN32 is untested by me.
+
+  Thanks to Martin Fong and others for supplying this.
+*/
+
+
+#ifdef WIN32
+
+#define AlignPage(add) (((add) + (malloc_getpagesize-1)) & \
+~(malloc_getpagesize-1))
+#define AlignPage64K(add) (((add) + (0x10000 - 1)) & ~(0x10000 - 1))
+
+/* resrve 64MB to insure large contiguous space */
+#define RESERVED_SIZE (1024*1024*64)
+#define NEXT_SIZE (2048*1024)
+#define TOP_MEMORY ((unsigned long)2*1024*1024*1024)
+
+struct GmListElement;
+typedef struct GmListElement GmListElement;
+
+struct GmListElement
+{
+	GmListElement* next;
+	void* base;
+};
+
+static GmListElement* head = 0;
+static unsigned int gNextAddress = 0;
+static unsigned int gAddressBase = 0;
+static unsigned int gAllocatedSize = 0;
+
+static
+GmListElement* makeGmListElement (void* bas)
+{
+	GmListElement* this;
+	this = (GmListElement*)(void*)LocalAlloc (0, sizeof (GmListElement));
+	assert (this);
+	if (this)
+	{
+		this->base = bas;
+		this->next = head;
+		head = this;
+	}
+	return this;
+}
+
+void gcleanup ()
+{
+	BOOL rval;
+	assert ( (head == NULL) || (head->base == (void*)gAddressBase));
+	if (gAddressBase && (gNextAddress - gAddressBase))
+	{
+		rval = VirtualFree ((void*)gAddressBase,
+							gNextAddress - gAddressBase,
+							MEM_DECOMMIT);
+	assert (rval);
+	}
+	while (head)
+	{
+		GmListElement* next = head->next;
+		rval = VirtualFree (head->base, 0, MEM_RELEASE);
+		assert (rval);
+		LocalFree (head);
+		head = next;
+	}
+}
+
+static
+void* findRegion (void* start_address, unsigned long size)
+{
+	MEMORY_BASIC_INFORMATION info;
+	if (size >= TOP_MEMORY) return NULL;
+
+	while ((unsigned long)start_address + size < TOP_MEMORY)
+	{
+		VirtualQuery (start_address, &info, sizeof (info));
+		if ((info.State == MEM_FREE) && (info.RegionSize >= size))
+			return start_address;
+		else
+		{
+			/* Requested region is not available so see if the */
+			/* next region is available.  Set 'start_address' */
+			/* to the next region and call 'VirtualQuery()' */
+			/* again. */
+
+			start_address = (char*)info.BaseAddress + info.RegionSize;
+
+			/* Make sure we start looking for the next region */
+			/* on the *next* 64K boundary.  Otherwise, even if */
+			/* the new region is free according to */
+			/* 'VirtualQuery()', the subsequent call to */
+			/* 'VirtualAlloc()' (which follows the call to */
+			/* this routine in 'wsbrk()') will round *down* */
+			/* the requested address to a 64K boundary which */
+			/* we already know is an address in the */
+			/* unavailable region.  Thus, the subsequent call */
+			/* to 'VirtualAlloc()' will fail and bring us back */
+			/* here, causing us to go into an infinite loop. */
+
+			start_address =
+				(void *) AlignPage64K((unsigned long) start_address);
+		}
+	}
+	return NULL;
+
+}
+
+
+void* wsbrk (long size)
+{
+	void* tmp;
+	if (size > 0)
+	{
+		if (gAddressBase == 0)
+		{
+			gAllocatedSize = max (RESERVED_SIZE, AlignPage (size));
+			gNextAddress = gAddressBase =
+				(unsigned int)VirtualAlloc (NULL, gAllocatedSize,
+											MEM_RESERVE, PAGE_NOACCESS);
+		} else if (AlignPage (gNextAddress + size) > (gAddressBase +
+gAllocatedSize))
+		{
+			long new_size = max (NEXT_SIZE, AlignPage (size));
+			void* new_address = (void*)(gAddressBase+gAllocatedSize);
+			do
+			{
+				new_address = findRegion (new_address, new_size);
+
+				if (new_address == 0)
+					return (void*)-1;
+
+				gAddressBase = gNextAddress =
+					(unsigned int)VirtualAlloc (new_address, new_size,
+												MEM_RESERVE, PAGE_NOACCESS);
+				/* repeat in case of race condition */
+				/* The region that we found has been snagged */
+				/* by another thread */
+			}
+			while (gAddressBase == 0);
+
+			assert (new_address == (void*)gAddressBase);
+
+			gAllocatedSize = new_size;
+
+			if (!makeGmListElement ((void*)gAddressBase))
+				return (void*)-1;
+		}
+		if ((size + gNextAddress) > AlignPage (gNextAddress))
+		{
+			void* res;
+			res = VirtualAlloc ((void*)AlignPage (gNextAddress),
+								(size + gNextAddress -
+								 AlignPage (gNextAddress)),
+								MEM_COMMIT, PAGE_READWRITE);
+			if (res == 0)
+				return (void*)-1;
+		}
+		tmp = (void*)gNextAddress;
+		gNextAddress = (unsigned int)tmp + size;
+		return tmp;
+	}
+	else if (size < 0)
+	{
+		unsigned int alignedGoal = AlignPage (gNextAddress + size);
+		/* Trim by releasing the virtual memory */
+		if (alignedGoal >= gAddressBase)
+		{
+			VirtualFree ((void*)alignedGoal, gNextAddress - alignedGoal,
+						 MEM_DECOMMIT);
+			gNextAddress = gNextAddress + size;
+			return (void*)gNextAddress;
+		}
+		else
+		{
+			VirtualFree ((void*)gAddressBase, gNextAddress - gAddressBase,
+						 MEM_DECOMMIT);
+			gNextAddress = gAddressBase;
+			return (void*)-1;
+		}
+	}
+	else
+	{
+		return (void*)gNextAddress;
+	}
+}
+
+#endif
+
+
+
+/*
+  Type declarations
+*/
+
+
+struct malloc_chunk
+{
+  INTERNAL_SIZE_T prev_size; /* Size of previous chunk (if free). */
+  INTERNAL_SIZE_T size;      /* Size in bytes, including overhead. */
+  struct malloc_chunk* fd;   /* double links -- used only if free. */
+  struct malloc_chunk* bk;
+} __attribute__((__may_alias__)) ;
+
+typedef struct malloc_chunk* mchunkptr;
+
+/*
+
+   malloc_chunk details:
+
+    (The following includes lightly edited explanations by Colin Plumb.)
+
+    Chunks of memory are maintained using a `boundary tag' method as
+    described in e.g., Knuth or Standish.  (See the paper by Paul
+    Wilson ftp://ftp.cs.utexas.edu/pub/garbage/allocsrv.ps for a
+    survey of such techniques.)  Sizes of free chunks are stored both
+    in the front of each chunk and at the end.  This makes
+    consolidating fragmented chunks into bigger chunks very fast.  The
+    size fields also hold bits representing whether chunks are free or
+    in use.
+
+    An allocated chunk looks like this:
+
+
+    chunk-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+	    |             Size of previous chunk, if allocated            | |
+	    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+	    |             Size of chunk, in bytes                         |P|
+      mem-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+	    |             User data starts here...                          .
+	    .                                                               .
+	    .             (malloc_usable_space() bytes)                     .
+	    .                                                               |
+nextchunk-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+	    |             Size of chunk                                     |
+	    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+
+
+    Where "chunk" is the front of the chunk for the purpose of most of
+    the malloc code, but "mem" is the pointer that is returned to the
+    user.  "Nextchunk" is the beginning of the next contiguous chunk.
+
+    Chunks always begin on even word boundries, so the mem portion
+    (which is returned to the user) is also on an even word boundary, and
+    thus double-word aligned.
+
+    Free chunks are stored in circular doubly-linked lists, and look like this:
+
+    chunk-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+	    |             Size of previous chunk                            |
+	    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+    `head:' |             Size of chunk, in bytes                         |P|
+      mem-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+	    |             Forward pointer to next chunk in list             |
+	    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+	    |             Back pointer to previous chunk in list            |
+	    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+	    |             Unused space (may be 0 bytes long)                .
+	    .                                                               .
+	    .                                                               |
+nextchunk-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+    `foot:' |             Size of chunk, in bytes                           |
+	    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+
+    The P (PREV_INUSE) bit, stored in the unused low-order bit of the
+    chunk size (which is always a multiple of two words), is an in-use
+    bit for the *previous* chunk.  If that bit is *clear*, then the
+    word before the current chunk size contains the previous chunk
+    size, and can be used to find the front of the previous chunk.
+    (The very first chunk allocated always has this bit set,
+    preventing access to non-existent (or non-owned) memory.)
+
+    Note that the `foot' of the current chunk is actually represented
+    as the prev_size of the NEXT chunk. (This makes it easier to
+    deal with alignments etc).
+
+    The two exceptions to all this are
+
+     1. The special chunk `top', which doesn't bother using the
+	trailing size field since there is no
+	next contiguous chunk that would have to index off it. (After
+	initialization, `top' is forced to always exist.  If it would
+	become less than MINSIZE bytes long, it is replenished via
+	malloc_extend_top.)
+
+     2. Chunks allocated via mmap, which have the second-lowest-order
+	bit (IS_MMAPPED) set in their size fields.  Because they are
+	never merged or traversed from any other chunk, they have no
+	foot size or inuse information.
+
+    Available chunks are kept in any of several places (all declared below):
+
+    * `av': An array of chunks serving as bin headers for consolidated
+       chunks. Each bin is doubly linked.  The bins are approximately
+       proportionally (log) spaced.  There are a lot of these bins
+       (128). This may look excessive, but works very well in
+       practice.  All procedures maintain the invariant that no
+       consolidated chunk physically borders another one. Chunks in
+       bins are kept in size order, with ties going to the
+       approximately least recently used chunk.
+
+       The chunks in each bin are maintained in decreasing sorted order by
+       size.  This is irrelevant for the small bins, which all contain
+       the same-sized chunks, but facilitates best-fit allocation for
+       larger chunks. (These lists are just sequential. Keeping them in
+       order almost never requires enough traversal to warrant using
+       fancier ordered data structures.)  Chunks of the same size are
+       linked with the most recently freed at the front, and allocations
+       are taken from the back.  This results in LRU or FIFO allocation
+       order, which tends to give each chunk an equal opportunity to be
+       consolidated with adjacent freed chunks, resulting in larger free
+       chunks and less fragmentation.
+
+    * `top': The top-most available chunk (i.e., the one bordering the
+       end of available memory) is treated specially. It is never
+       included in any bin, is used only if no other chunk is
+       available, and is released back to the system if it is very
+       large (see M_TRIM_THRESHOLD).
+
+    * `last_remainder': A bin holding only the remainder of the
+       most recently split (non-top) chunk. This bin is checked
+       before other non-fitting chunks, so as to provide better
+       locality for runs of sequentially allocated chunks.
+
+    *  Implicitly, through the host system's memory mapping tables.
+       If supported, requests greater than a threshold are usually
+       serviced via calls to mmap, and then later released via munmap.
+
+*/
+
+/*  sizes, alignments */
+
+#define SIZE_SZ                (sizeof(INTERNAL_SIZE_T))
+#define MALLOC_ALIGNMENT       (SIZE_SZ + SIZE_SZ)
+#define MALLOC_ALIGN_MASK      (MALLOC_ALIGNMENT - 1)
+#define MINSIZE                (sizeof(struct malloc_chunk))
+
+/* conversion from malloc headers to user pointers, and back */
+
+#define chunk2mem(p)   ((Void_t*)((char*)(p) + 2*SIZE_SZ))
+#define mem2chunk(mem) ((mchunkptr)((char*)(mem) - 2*SIZE_SZ))
+
+/* pad request bytes into a usable size */
+
+#define request2size(req) \
+ (((long)((req) + (SIZE_SZ + MALLOC_ALIGN_MASK)) < \
+  (long)(MINSIZE + MALLOC_ALIGN_MASK)) ? MINSIZE : \
+   (((req) + (SIZE_SZ + MALLOC_ALIGN_MASK)) & ~(MALLOC_ALIGN_MASK)))
+
+/* Check if m has acceptable alignment */
+
+#define aligned_OK(m)    (((unsigned long)((m)) & (MALLOC_ALIGN_MASK)) == 0)
+
+
+
+
+/*
+  Physical chunk operations
+*/
+
+
+/* size field is or'ed with PREV_INUSE when previous adjacent chunk in use */
+
+#define PREV_INUSE 0x1
+
+/* size field is or'ed with IS_MMAPPED if the chunk was obtained with mmap() */
+
+#define IS_MMAPPED 0x2
+
+/* Bits to mask off when extracting size */
+
+#define SIZE_BITS (PREV_INUSE|IS_MMAPPED)
+
+
+/* Ptr to next physical malloc_chunk. */
+
+#define next_chunk(p) ((mchunkptr)( ((char*)(p)) + ((p)->size & ~PREV_INUSE) ))
+
+/* Ptr to previous physical malloc_chunk */
+
+#define prev_chunk(p)\
+   ((mchunkptr)( ((char*)(p)) - ((p)->prev_size) ))
+
+
+/* Treat space at ptr + offset as a chunk */
+
+#define chunk_at_offset(p, s)  ((mchunkptr)(((char*)(p)) + (s)))
+
+
+
+
+/*
+  Dealing with use bits
+*/
+
+/* extract p's inuse bit */
+
+#define inuse(p)\
+((((mchunkptr)(((char*)(p))+((p)->size & ~PREV_INUSE)))->size) & PREV_INUSE)
+
+/* extract inuse bit of previous chunk */
+
+#define prev_inuse(p)  ((p)->size & PREV_INUSE)
+
+/* check for mmap()'ed chunk */
+
+#define chunk_is_mmapped(p) ((p)->size & IS_MMAPPED)
+
+/* set/clear chunk as in use without otherwise disturbing */
+
+#define set_inuse(p)\
+((mchunkptr)(((char*)(p)) + ((p)->size & ~PREV_INUSE)))->size |= PREV_INUSE
+
+#define clear_inuse(p)\
+((mchunkptr)(((char*)(p)) + ((p)->size & ~PREV_INUSE)))->size &= ~(PREV_INUSE)
+
+/* check/set/clear inuse bits in known places */
+
+#define inuse_bit_at_offset(p, s)\
+ (((mchunkptr)(((char*)(p)) + (s)))->size & PREV_INUSE)
+
+#define set_inuse_bit_at_offset(p, s)\
+ (((mchunkptr)(((char*)(p)) + (s)))->size |= PREV_INUSE)
+
+#define clear_inuse_bit_at_offset(p, s)\
+ (((mchunkptr)(((char*)(p)) + (s)))->size &= ~(PREV_INUSE))
+
+
+
+
+/*
+  Dealing with size fields
+*/
+
+/* Get size, ignoring use bits */
+
+#define chunksize(p)          ((p)->size & ~(SIZE_BITS))
+
+/* Set size at head, without disturbing its use bit */
+
+#define set_head_size(p, s)   ((p)->size = (((p)->size & PREV_INUSE) | (s)))
+
+/* Set size/use ignoring previous bits in header */
+
+#define set_head(p, s)        ((p)->size = (s))
+
+/* Set size at footer (only when chunk is not in use) */
+
+#define set_foot(p, s)   (((mchunkptr)((char*)(p) + (s)))->prev_size = (s))
+
+
+
+
+
+/*
+   Bins
+
+    The bins, `av_' are an array of pairs of pointers serving as the
+    heads of (initially empty) doubly-linked lists of chunks, laid out
+    in a way so that each pair can be treated as if it were in a
+    malloc_chunk. (This way, the fd/bk offsets for linking bin heads
+    and chunks are the same).
+
+    Bins for sizes < 512 bytes contain chunks of all the same size, spaced
+    8 bytes apart. Larger bins are approximately logarithmically
+    spaced. (See the table below.) The `av_' array is never mentioned
+    directly in the code, but instead via bin access macros.
+
+    Bin layout:
+
+    64 bins of size       8
+    32 bins of size      64
+    16 bins of size     512
+     8 bins of size    4096
+     4 bins of size   32768
+     2 bins of size  262144
+     1 bin  of size what's left
+
+    There is actually a little bit of slop in the numbers in bin_index
+    for the sake of speed. This makes no difference elsewhere.
+
+    The special chunks `top' and `last_remainder' get their own bins,
+    (this is implemented via yet more trickery with the av_ array),
+    although `top' is never properly linked to its bin since it is
+    always handled specially.
+
+*/
+
+#define NAV             128   /* number of bins */
+
+typedef struct malloc_chunk* mbinptr;
+
+/* access macros */
+
+#define bin_at(i)      ((mbinptr)((char*)&(av_[2*(i) + 2]) - 2*SIZE_SZ))
+#define next_bin(b)    ((mbinptr)((char*)(b) + 2 * sizeof(mbinptr)))
+#define prev_bin(b)    ((mbinptr)((char*)(b) - 2 * sizeof(mbinptr)))
+
+/*
+   The first 2 bins are never indexed. The corresponding av_ cells are instead
+   used for bookkeeping. This is not to save space, but to simplify
+   indexing, maintain locality, and avoid some initialization tests.
+*/
+
+#define top            (av_[2])          /* The topmost chunk */
+#define last_remainder (bin_at(1))       /* remainder from last split */
+
+
+/*
+   Because top initially points to its own bin with initial
+   zero size, thus forcing extension on the first malloc request,
+   we avoid having any special code in malloc to check whether
+   it even exists yet. But we still need to in malloc_extend_top.
+*/
+
+#define initial_top    ((mchunkptr)(bin_at(0)))
+
+/* Helper macro to initialize bins */
+
+#define IAV(i)  bin_at(i), bin_at(i)
+
+static mbinptr av_[NAV * 2 + 2] = {
+ NULL, NULL,
+ IAV(0),   IAV(1),   IAV(2),   IAV(3),   IAV(4),   IAV(5),   IAV(6),   IAV(7),
+ IAV(8),   IAV(9),   IAV(10),  IAV(11),  IAV(12),  IAV(13),  IAV(14),  IAV(15),
+ IAV(16),  IAV(17),  IAV(18),  IAV(19),  IAV(20),  IAV(21),  IAV(22),  IAV(23),
+ IAV(24),  IAV(25),  IAV(26),  IAV(27),  IAV(28),  IAV(29),  IAV(30),  IAV(31),
+ IAV(32),  IAV(33),  IAV(34),  IAV(35),  IAV(36),  IAV(37),  IAV(38),  IAV(39),
+ IAV(40),  IAV(41),  IAV(42),  IAV(43),  IAV(44),  IAV(45),  IAV(46),  IAV(47),
+ IAV(48),  IAV(49),  IAV(50),  IAV(51),  IAV(52),  IAV(53),  IAV(54),  IAV(55),
+ IAV(56),  IAV(57),  IAV(58),  IAV(59),  IAV(60),  IAV(61),  IAV(62),  IAV(63),
+ IAV(64),  IAV(65),  IAV(66),  IAV(67),  IAV(68),  IAV(69),  IAV(70),  IAV(71),
+ IAV(72),  IAV(73),  IAV(74),  IAV(75),  IAV(76),  IAV(77),  IAV(78),  IAV(79),
+ IAV(80),  IAV(81),  IAV(82),  IAV(83),  IAV(84),  IAV(85),  IAV(86),  IAV(87),
+ IAV(88),  IAV(89),  IAV(90),  IAV(91),  IAV(92),  IAV(93),  IAV(94),  IAV(95),
+ IAV(96),  IAV(97),  IAV(98),  IAV(99),  IAV(100), IAV(101), IAV(102), IAV(103),
+ IAV(104), IAV(105), IAV(106), IAV(107), IAV(108), IAV(109), IAV(110), IAV(111),
+ IAV(112), IAV(113), IAV(114), IAV(115), IAV(116), IAV(117), IAV(118), IAV(119),
+ IAV(120), IAV(121), IAV(122), IAV(123), IAV(124), IAV(125), IAV(126), IAV(127)
+};
+
+ulong mem_malloc_start = 0;
+ulong mem_malloc_end = 0;
+ulong mem_malloc_brk = 0;
+
+void *sbrk(ptrdiff_t increment)
+{
+	ulong old = mem_malloc_brk;
+	ulong new = old + increment;
+
+	/*
+	 * if we are giving memory back make sure we clear it out since
+	 * we set MORECORE_CLEARS to 1
+	 */
+	if (increment < 0)
+		memset((void *)new, 0, -increment);
+
+	if ((new < mem_malloc_start) || (new > mem_malloc_end))
+		return (void *)MORECORE_FAILURE;
+
+	mem_malloc_brk = new;
+
+	return (void *)old;
+}
+
+void mem_malloc_init(ulong start, ulong size)
+{
+	mem_malloc_start = start;
+	mem_malloc_end = start + size;
+	mem_malloc_brk = start;
+
+	memset((void *)mem_malloc_start, 0, size);
+    printf("malloc memory space: 0x%lx~0x%lx\n", start, start+size);
+}
+
+/* field-extraction macros */
+
+#define first(b) ((b)->fd)
+#define last(b)  ((b)->bk)
+
+/*
+  Indexing into bins
+*/
+
+#define bin_index(sz)                                                          \
+(((((unsigned long)(sz)) >> 9) ==    0) ?       (((unsigned long)(sz)) >>  3): \
+ ((((unsigned long)(sz)) >> 9) <=    4) ?  56 + (((unsigned long)(sz)) >>  6): \
+ ((((unsigned long)(sz)) >> 9) <=   20) ?  91 + (((unsigned long)(sz)) >>  9): \
+ ((((unsigned long)(sz)) >> 9) <=   84) ? 110 + (((unsigned long)(sz)) >> 12): \
+ ((((unsigned long)(sz)) >> 9) <=  340) ? 119 + (((unsigned long)(sz)) >> 15): \
+ ((((unsigned long)(sz)) >> 9) <= 1364) ? 124 + (((unsigned long)(sz)) >> 18): \
+					  126)
+/*
+  bins for chunks < 512 are all spaced 8 bytes apart, and hold
+  identically sized chunks. This is exploited in malloc.
+*/
+
+#define MAX_SMALLBIN         63
+#define MAX_SMALLBIN_SIZE   512
+#define SMALLBIN_WIDTH        8
+
+#define smallbin_index(sz)  (((unsigned long)(sz)) >> 3)
+
+/*
+   Requests are `small' if both the corresponding and the next bin are small
+*/
+
+#define is_small_request(nb) (nb < MAX_SMALLBIN_SIZE - SMALLBIN_WIDTH)
+
+
+
+/*
+    To help compensate for the large number of bins, a one-level index
+    structure is used for bin-by-bin searching.  `binblocks' is a
+    one-word bitvector recording whether groups of BINBLOCKWIDTH bins
+    have any (possibly) non-empty bins, so they can be skipped over
+    all at once during during traversals. The bits are NOT always
+    cleared as soon as all bins in a block are empty, but instead only
+    when all are noticed to be empty during traversal in malloc.
+*/
+
+#define BINBLOCKWIDTH     4   /* bins per block */
+
+#define binblocks_r     ((INTERNAL_SIZE_T)av_[1]) /* bitvector of nonempty blocks */
+#define binblocks_w     (av_[1])
+
+/* bin<->block macros */
+
+#define idx2binblock(ix)    ((unsigned)1 << (ix / BINBLOCKWIDTH))
+#define mark_binblock(ii)   (binblocks_w = (mbinptr)(binblocks_r | idx2binblock(ii)))
+#define clear_binblock(ii)  (binblocks_w = (mbinptr)(binblocks_r & ~(idx2binblock(ii))))
+
+
+
+
+
+/*  Other static bookkeeping data */
+
+/* variables holding tunable values */
+
+static unsigned long trim_threshold   = DEFAULT_TRIM_THRESHOLD;
+static unsigned long top_pad          = DEFAULT_TOP_PAD;
+static unsigned int  n_mmaps_max      = DEFAULT_MMAP_MAX;
+static unsigned long mmap_threshold   = DEFAULT_MMAP_THRESHOLD;
+
+/* The first value returned from sbrk */
+static char* sbrk_base = (char*)(-1);
+
+/* The maximum memory obtained from system via sbrk */
+static unsigned long max_sbrked_mem = 0;
+
+/* The maximum via either sbrk or mmap */
+static unsigned long max_total_mem = 0;
+
+/* internal working copy of mallinfo */
+static struct mallinfo current_mallinfo = {  0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
+
+/* The total memory obtained from system via sbrk */
+#define sbrked_mem  (current_mallinfo.arena)
+
+/* Tracking mmaps */
+
+#ifdef DEBUG
+static unsigned int n_mmaps = 0;
+#endif	/* DEBUG */
+static unsigned long mmapped_mem = 0;
+#if HAVE_MMAP
+static unsigned int max_n_mmaps = 0;
+static unsigned long max_mmapped_mem = 0;
+#endif
+
+
+
+/*
+  Debugging support
+*/
+
+#ifdef DEBUG
+
+
+/*
+  These routines make a number of assertions about the states
+  of data structures that should be true at all times. If any
+  are not true, it's very likely that a user program has somehow
+  trashed memory. (It's also possible that there is a coding error
+  in malloc. In which case, please report it!)
+*/
+
+#if __STD_C
+static void do_check_chunk(mchunkptr p)
+#else
+static void do_check_chunk(p) mchunkptr p;
+#endif
+{
+  INTERNAL_SIZE_T sz = p->size & ~PREV_INUSE;
+
+  /* No checkable chunk is mmapped */
+  assert(!chunk_is_mmapped(p));
+
+  /* Check for legal address ... */
+  assert((char*)p >= sbrk_base);
+  if (p != top)
+    assert((char*)p + sz <= (char*)top);
+  else
+    assert((char*)p + sz <= sbrk_base + sbrked_mem);
+
+}
+
+
+#if __STD_C
+static void do_check_free_chunk(mchunkptr p)
+#else
+static void do_check_free_chunk(p) mchunkptr p;
+#endif
+{
+  INTERNAL_SIZE_T sz = p->size & ~PREV_INUSE;
+  mchunkptr next = chunk_at_offset(p, sz);
+
+  do_check_chunk(p);
+
+  /* Check whether it claims to be free ... */
+  assert(!inuse(p));
+
+  /* Unless a special marker, must have OK fields */
+  if ((long)sz >= (long)MINSIZE)
+  {
+    assert((sz & MALLOC_ALIGN_MASK) == 0);
+    assert(aligned_OK(chunk2mem(p)));
+    /* ... matching footer field */
+    assert(next->prev_size == sz);
+    /* ... and is fully consolidated */
+    assert(prev_inuse(p));
+    assert (next == top || inuse(next));
+
+    /* ... and has minimally sane links */
+    assert(p->fd->bk == p);
+    assert(p->bk->fd == p);
+  }
+  else /* markers are always of size SIZE_SZ */
+    assert(sz == SIZE_SZ);
+}
+
+#if __STD_C
+static void do_check_inuse_chunk(mchunkptr p)
+#else
+static void do_check_inuse_chunk(p) mchunkptr p;
+#endif
+{
+  mchunkptr next = next_chunk(p);
+  do_check_chunk(p);
+
+  /* Check whether it claims to be in use ... */
+  assert(inuse(p));
+
+  /* ... and is surrounded by OK chunks.
+    Since more things can be checked with free chunks than inuse ones,
+    if an inuse chunk borders them and debug is on, it's worth doing them.
+  */
+  if (!prev_inuse(p))
+  {
+    mchunkptr prv = prev_chunk(p);
+    assert(next_chunk(prv) == p);
+    do_check_free_chunk(prv);
+  }
+  if (next == top)
+  {
+    assert(prev_inuse(next));
+    assert(chunksize(next) >= MINSIZE);
+  }
+  else if (!inuse(next))
+    do_check_free_chunk(next);
+
+}
+
+#if __STD_C
+static void do_check_malloced_chunk(mchunkptr p, INTERNAL_SIZE_T s)
+#else
+static void do_check_malloced_chunk(p, s) mchunkptr p; INTERNAL_SIZE_T s;
+#endif
+{
+  INTERNAL_SIZE_T sz = p->size & ~PREV_INUSE;
+  long room = sz - s;
+
+  do_check_inuse_chunk(p);
+
+  /* Legal size ... */
+  assert((long)sz >= (long)MINSIZE);
+  assert((sz & MALLOC_ALIGN_MASK) == 0);
+  assert(room >= 0);
+  assert(room < (long)MINSIZE);
+
+  /* ... and alignment */
+  assert(aligned_OK(chunk2mem(p)));
+
+
+  /* ... and was allocated at front of an available chunk */
+  assert(prev_inuse(p));
+
+}
+
+
+#define check_free_chunk(P)  do_check_free_chunk(P)
+#define check_inuse_chunk(P) do_check_inuse_chunk(P)
+#define check_chunk(P) do_check_chunk(P)
+#define check_malloced_chunk(P,N) do_check_malloced_chunk(P,N)
+#else
+#define check_free_chunk(P)
+#define check_inuse_chunk(P)
+#define check_chunk(P)
+#define check_malloced_chunk(P,N)
+#endif
+
+
+
+/*
+  Macro-based internal utilities
+*/
+
+
+/*
+  Linking chunks in bin lists.
+  Call these only with variables, not arbitrary expressions, as arguments.
+*/
+
+/*
+  Place chunk p of size s in its bin, in size order,
+  putting it ahead of others of same size.
+*/
+
+
+#define frontlink(P, S, IDX, BK, FD)                                          \
+{                                                                             \
+  if (S < MAX_SMALLBIN_SIZE)                                                  \
+  {                                                                           \
+    IDX = smallbin_index(S);                                                  \
+    mark_binblock(IDX);                                                       \
+    BK = bin_at(IDX);                                                         \
+    FD = BK->fd;                                                              \
+    P->bk = BK;                                                               \
+    P->fd = FD;                                                               \
+    FD->bk = BK->fd = P;                                                      \
+  }                                                                           \
+  else                                                                        \
+  {                                                                           \
+    IDX = bin_index(S);                                                       \
+    BK = bin_at(IDX);                                                         \
+    FD = BK->fd;                                                              \
+    if (FD == BK) mark_binblock(IDX);                                         \
+    else                                                                      \
+    {                                                                         \
+      while (FD != BK && S < chunksize(FD)) FD = FD->fd;                      \
+      BK = FD->bk;                                                            \
+    }                                                                         \
+    P->bk = BK;                                                               \
+    P->fd = FD;                                                               \
+    FD->bk = BK->fd = P;                                                      \
+  }                                                                           \
+}
+
+
+/* take a chunk off a list */
+
+#define unlink(P, BK, FD)                                                     \
+{                                                                             \
+  BK = P->bk;                                                                 \
+  FD = P->fd;                                                                 \
+  FD->bk = BK;                                                                \
+  BK->fd = FD;                                                                \
+}                                                                             \
+
+/* Place p as the last remainder */
+
+#define link_last_remainder(P)                                                \
+{                                                                             \
+  last_remainder->fd = last_remainder->bk =  P;                               \
+  P->fd = P->bk = last_remainder;                                             \
+}
+
+/* Clear the last_remainder bin */
+
+#define clear_last_remainder \
+  (last_remainder->fd = last_remainder->bk = last_remainder)
+
+
+
+
+
+/* Routines dealing with mmap(). */
+
+#if HAVE_MMAP
+
+#if __STD_C
+static mchunkptr mmap_chunk(size_t size)
+#else
+static mchunkptr mmap_chunk(size) size_t size;
+#endif
+{
+  size_t page_mask = malloc_getpagesize - 1;
+  mchunkptr p;
+
+#ifndef MAP_ANONYMOUS
+  static int fd = -1;
+#endif
+
+  if(n_mmaps >= n_mmaps_max) return 0; /* too many regions */
+
+  /* For mmapped chunks, the overhead is one SIZE_SZ unit larger, because
+   * there is no following chunk whose prev_size field could be used.
+   */
+  size = (size + SIZE_SZ + page_mask) & ~page_mask;
+
+#ifdef MAP_ANONYMOUS
+  p = (mchunkptr)mmap(0, size, PROT_READ|PROT_WRITE,
+		      MAP_PRIVATE|MAP_ANONYMOUS, -1, 0);
+#else /* !MAP_ANONYMOUS */
+  if (fd < 0)
+  {
+    fd = open("/dev/zero", O_RDWR);
+    if(fd < 0) return 0;
+  }
+  p = (mchunkptr)mmap(0, size, PROT_READ|PROT_WRITE, MAP_PRIVATE, fd, 0);
+#endif
+
+  if(p == (mchunkptr)-1) return 0;
+
+  n_mmaps++;
+  if (n_mmaps > max_n_mmaps) max_n_mmaps = n_mmaps;
+
+  /* We demand that eight bytes into a page must be 8-byte aligned. */
+  assert(aligned_OK(chunk2mem(p)));
+
+  /* The offset to the start of the mmapped region is stored
+   * in the prev_size field of the chunk; normally it is zero,
+   * but that can be changed in memalign().
+   */
+  p->prev_size = 0;
+  set_head(p, size|IS_MMAPPED);
+
+  mmapped_mem += size;
+  if ((unsigned long)mmapped_mem > (unsigned long)max_mmapped_mem)
+    max_mmapped_mem = mmapped_mem;
+  if ((unsigned long)(mmapped_mem + sbrked_mem) > (unsigned long)max_total_mem)
+    max_total_mem = mmapped_mem + sbrked_mem;
+  return p;
+}
+
+#if __STD_C
+static void munmap_chunk(mchunkptr p)
+#else
+static void munmap_chunk(p) mchunkptr p;
+#endif
+{
+  INTERNAL_SIZE_T size = chunksize(p);
+  int ret;
+
+  assert (chunk_is_mmapped(p));
+  assert(! ((char*)p >= sbrk_base && (char*)p < sbrk_base + sbrked_mem));
+  assert((n_mmaps > 0));
+  assert(((p->prev_size + size) & (malloc_getpagesize-1)) == 0);
+
+  n_mmaps--;
+  mmapped_mem -= (size + p->prev_size);
+
+  ret = munmap((char *)p - p->prev_size, size + p->prev_size);
+
+  /* munmap returns non-zero on failure */
+  assert(ret == 0);
+}
+
+#if HAVE_MREMAP
+
+#if __STD_C
+static mchunkptr mremap_chunk(mchunkptr p, size_t new_size)
+#else
+static mchunkptr mremap_chunk(p, new_size) mchunkptr p; size_t new_size;
+#endif
+{
+  size_t page_mask = malloc_getpagesize - 1;
+  INTERNAL_SIZE_T offset = p->prev_size;
+  INTERNAL_SIZE_T size = chunksize(p);
+  char *cp;
+
+  assert (chunk_is_mmapped(p));
+  assert(! ((char*)p >= sbrk_base && (char*)p < sbrk_base + sbrked_mem));
+  assert((n_mmaps > 0));
+  assert(((size + offset) & (malloc_getpagesize-1)) == 0);
+
+  /* Note the extra SIZE_SZ overhead as in mmap_chunk(). */
+  new_size = (new_size + offset + SIZE_SZ + page_mask) & ~page_mask;
+
+  cp = (char *)mremap((char *)p - offset, size + offset, new_size, 1);
+
+  if (cp == (char *)-1) return 0;
+
+  p = (mchunkptr)(cp + offset);
+
+  assert(aligned_OK(chunk2mem(p)));
+
+  assert((p->prev_size == offset));
+  set_head(p, (new_size - offset)|IS_MMAPPED);
+
+  mmapped_mem -= size + offset;
+  mmapped_mem += new_size;
+  if ((unsigned long)mmapped_mem > (unsigned long)max_mmapped_mem)
+    max_mmapped_mem = mmapped_mem;
+  if ((unsigned long)(mmapped_mem + sbrked_mem) > (unsigned long)max_total_mem)
+    max_total_mem = mmapped_mem + sbrked_mem;
+  return p;
+}
+
+#endif /* HAVE_MREMAP */
+
+#endif /* HAVE_MMAP */
+
+
+
+
+/*
+  Extend the top-most chunk by obtaining memory from system.
+  Main interface to sbrk (but see also malloc_trim).
+*/
+
+#if __STD_C
+static void malloc_extend_top(INTERNAL_SIZE_T nb)
+#else
+static void malloc_extend_top(nb) INTERNAL_SIZE_T nb;
+#endif
+{
+  char*     brk;                  /* return value from sbrk */
+  INTERNAL_SIZE_T front_misalign; /* unusable bytes at front of sbrked space */
+  INTERNAL_SIZE_T correction;     /* bytes for 2nd sbrk call */
+  char*     new_brk;              /* return of 2nd sbrk call */
+  INTERNAL_SIZE_T top_size;       /* new size of top chunk */
+
+  mchunkptr old_top     = top;  /* Record state of old top */
+  INTERNAL_SIZE_T old_top_size = chunksize(old_top);
+  char*     old_end      = (char*)(chunk_at_offset(old_top, old_top_size));
+
+  /* Pad request with top_pad plus minimal overhead */
+
+  INTERNAL_SIZE_T    sbrk_size     = nb + top_pad + MINSIZE;
+  unsigned long pagesz    = malloc_getpagesize;
+
+  /* If not the first time through, round to preserve page boundary */
+  /* Otherwise, we need to correct to a page size below anyway. */
+  /* (We also correct below if an intervening foreign sbrk call.) */
+
+  if (sbrk_base != (char*)(-1))
+    sbrk_size = (sbrk_size + (pagesz - 1)) & ~(pagesz - 1);
+
+  brk = (char*)(MORECORE (sbrk_size));
+
+  /* Fail if sbrk failed or if a foreign sbrk call killed our space */
+  if (brk == (char*)(MORECORE_FAILURE) ||
+      (brk < old_end && old_top != initial_top))
+    return;
+
+  sbrked_mem += sbrk_size;
+
+  if (brk == old_end) /* can just add bytes to current top */
+  {
+    top_size = sbrk_size + old_top_size;
+    set_head(top, top_size | PREV_INUSE);
+  }
+  else
+  {
+    if (sbrk_base == (char*)(-1))  /* First time through. Record base */
+      sbrk_base = brk;
+    else  /* Someone else called sbrk().  Count those bytes as sbrked_mem. */
+      sbrked_mem += brk - (char*)old_end;
+
+    /* Guarantee alignment of first new chunk made from this space */
+    front_misalign = (unsigned long)chunk2mem(brk) & MALLOC_ALIGN_MASK;
+    if (front_misalign > 0)
+    {
+      correction = (MALLOC_ALIGNMENT) - front_misalign;
+      brk += correction;
+    }
+    else
+      correction = 0;
+
+    /* Guarantee the next brk will be at a page boundary */
+
+    correction += ((((unsigned long)(brk + sbrk_size))+(pagesz-1)) &
+		   ~(pagesz - 1)) - ((unsigned long)(brk + sbrk_size));
+
+    /* Allocate correction */
+    new_brk = (char*)(MORECORE (correction));
+    if (new_brk == (char*)(MORECORE_FAILURE)) return;
+
+    sbrked_mem += correction;
+
+    top = (mchunkptr)brk;
+    top_size = new_brk - brk + correction;
+    set_head(top, top_size | PREV_INUSE);
+
+    if (old_top != initial_top)
+    {
+
+      /* There must have been an intervening foreign sbrk call. */
+      /* A double fencepost is necessary to prevent consolidation */
+
+      /* If not enough space to do this, then user did something very wrong */
+      if (old_top_size < MINSIZE)
+      {
+	set_head(top, PREV_INUSE); /* will force null return from malloc */
+	return;
+      }
+
+      /* Also keep size a multiple of MALLOC_ALIGNMENT */
+      old_top_size = (old_top_size - 3*SIZE_SZ) & ~MALLOC_ALIGN_MASK;
+      set_head_size(old_top, old_top_size);
+      chunk_at_offset(old_top, old_top_size          )->size =
+	SIZE_SZ|PREV_INUSE;
+      chunk_at_offset(old_top, old_top_size + SIZE_SZ)->size =
+	SIZE_SZ|PREV_INUSE;
+      /* If possible, release the rest. */
+      if (old_top_size >= MINSIZE)
+	fREe(chunk2mem(old_top));
+    }
+  }
+
+  if ((unsigned long)sbrked_mem > (unsigned long)max_sbrked_mem)
+    max_sbrked_mem = sbrked_mem;
+  if ((unsigned long)(mmapped_mem + sbrked_mem) > (unsigned long)max_total_mem)
+    max_total_mem = mmapped_mem + sbrked_mem;
+
+  /* We always land on a page boundary */
+  assert(((unsigned long)((char*)top + top_size) & (pagesz - 1)) == 0);
+}
+
+
+
+
+/* Main public routines */
+
+
+/*
+  Malloc Algorthim:
+
+    The requested size is first converted into a usable form, `nb'.
+    This currently means to add 4 bytes overhead plus possibly more to
+    obtain 8-byte alignment and/or to obtain a size of at least
+    MINSIZE (currently 16 bytes), the smallest allocatable size.
+    (All fits are considered `exact' if they are within MINSIZE bytes.)
+
+    From there, the first successful of the following steps is taken:
+
+      1. The bin corresponding to the request size is scanned, and if
+	 a chunk of exactly the right size is found, it is taken.
+
+      2. The most recently remaindered chunk is used if it is big
+	 enough.  This is a form of (roving) first fit, used only in
+	 the absence of exact fits. Runs of consecutive requests use
+	 the remainder of the chunk used for the previous such request
+	 whenever possible. This limited use of a first-fit style
+	 allocation strategy tends to give contiguous chunks
+	 coextensive lifetimes, which improves locality and can reduce
+	 fragmentation in the long run.
+
+      3. Other bins are scanned in increasing size order, using a
+	 chunk big enough to fulfill the request, and splitting off
+	 any remainder.  This search is strictly by best-fit; i.e.,
+	 the smallest (with ties going to approximately the least
+	 recently used) chunk that fits is selected.
+
+      4. If large enough, the chunk bordering the end of memory
+	 (`top') is split off. (This use of `top' is in accord with
+	 the best-fit search rule.  In effect, `top' is treated as
+	 larger (and thus less well fitting) than any other available
+	 chunk since it can be extended to be as large as necessary
+	 (up to system limitations).
+
+      5. If the request size meets the mmap threshold and the
+	 system supports mmap, and there are few enough currently
+	 allocated mmapped regions, and a call to mmap succeeds,
+	 the request is allocated via direct memory mapping.
+
+      6. Otherwise, the top of memory is extended by
+	 obtaining more space from the system (normally using sbrk,
+	 but definable to anything else via the MORECORE macro).
+	 Memory is gathered from the system (in system page-sized
+	 units) in a way that allows chunks obtained across different
+	 sbrk calls to be consolidated, but does not require
+	 contiguous memory. Thus, it should be safe to intersperse
+	 mallocs with other sbrk calls.
+
+
+      All allocations are made from the the `lowest' part of any found
+      chunk. (The implementation invariant is that prev_inuse is
+      always true of any allocated chunk; i.e., that each allocated
+      chunk borders either a previously allocated and still in-use chunk,
+      or the base of its memory arena.)
+
+*/
+
+#if __STD_C
+Void_t* mALLOc(size_t bytes)
+#else
+Void_t* mALLOc(bytes) size_t bytes;
+#endif
+{
+  mchunkptr victim;                  /* inspected/selected chunk */
+  INTERNAL_SIZE_T victim_size;       /* its size */
+  int       idx;                     /* index for bin traversal */
+  mbinptr   bin;                     /* associated bin */
+  mchunkptr remainder;               /* remainder from a split */
+  long      remainder_size;          /* its size */
+  int       remainder_index;         /* its bin index */
+  unsigned long block;               /* block traverser bit */
+  int       startidx;                /* first bin of a traversed block */
+  mchunkptr fwd;                     /* misc temp for linking */
+  mchunkptr bck;                     /* misc temp for linking */
+  mbinptr q;                         /* misc temp */
+
+  INTERNAL_SIZE_T nb;
+
+  /* check if mem_malloc_init() was run */
+  if ((mem_malloc_start == 0) && (mem_malloc_end == 0)) {
+    /* not initialized yet */
+    return NULL;
+  }
+
+  if ((long)bytes < 0) return NULL;
+
+  nb = request2size(bytes);  /* padded request size; */
+
+  /* Check for exact match in a bin */
+
+  if (is_small_request(nb))  /* Faster version for small requests */
+  {
+    idx = smallbin_index(nb);
+
+    /* No traversal or size check necessary for small bins.  */
+
+    q = bin_at(idx);
+    victim = last(q);
+
+    /* Also scan the next one, since it would have a remainder < MINSIZE */
+    if (victim == q)
+    {
+      q = next_bin(q);
+      victim = last(q);
+    }
+    if (victim != q)
+    {
+      victim_size = chunksize(victim);
+      unlink(victim, bck, fwd);
+      set_inuse_bit_at_offset(victim, victim_size);
+      check_malloced_chunk(victim, nb);
+      return chunk2mem(victim);
+    }
+
+    idx += 2; /* Set for bin scan below. We've already scanned 2 bins. */
+
+  }
+  else
+  {
+    idx = bin_index(nb);
+    bin = bin_at(idx);
+
+    for (victim = last(bin); victim != bin; victim = victim->bk)
+    {
+      victim_size = chunksize(victim);
+      remainder_size = victim_size - nb;
+
+      if (remainder_size >= (long)MINSIZE) /* too big */
+      {
+	--idx; /* adjust to rescan below after checking last remainder */
+	break;
+      }
+
+      else if (remainder_size >= 0) /* exact fit */
+      {
+	unlink(victim, bck, fwd);
+	set_inuse_bit_at_offset(victim, victim_size);
+	check_malloced_chunk(victim, nb);
+	return chunk2mem(victim);
+      }
+    }
+
+    ++idx;
+
+  }
+
+  /* Try to use the last split-off remainder */
+
+  if ( (victim = last_remainder->fd) != last_remainder)
+  {
+    victim_size = chunksize(victim);
+    remainder_size = victim_size - nb;
+
+    if (remainder_size >= (long)MINSIZE) /* re-split */
+    {
+      remainder = chunk_at_offset(victim, nb);
+      set_head(victim, nb | PREV_INUSE);
+      link_last_remainder(remainder);
+      set_head(remainder, remainder_size | PREV_INUSE);
+      set_foot(remainder, remainder_size);
+      check_malloced_chunk(victim, nb);
+      return chunk2mem(victim);
+    }
+
+    clear_last_remainder;
+
+    if (remainder_size >= 0)  /* exhaust */
+    {
+      set_inuse_bit_at_offset(victim, victim_size);
+      check_malloced_chunk(victim, nb);
+      return chunk2mem(victim);
+    }
+
+    /* Else place in bin */
+
+    frontlink(victim, victim_size, remainder_index, bck, fwd);
+  }
+
+  /*
+     If there are any possibly nonempty big-enough blocks,
+     search for best fitting chunk by scanning bins in blockwidth units.
+  */
+
+  if ( (block = idx2binblock(idx)) <= binblocks_r)
+  {
+
+    /* Get to the first marked block */
+
+    if ( (block & binblocks_r) == 0)
+    {
+      /* force to an even block boundary */
+      idx = (idx & ~(BINBLOCKWIDTH - 1)) + BINBLOCKWIDTH;
+      block <<= 1;
+      while ((block & binblocks_r) == 0)
+      {
+	idx += BINBLOCKWIDTH;
+	block <<= 1;
+      }
+    }
+
+    /* For each possibly nonempty block ... */
+    for (;;)
+    {
+      startidx = idx;          /* (track incomplete blocks) */
+      q = bin = bin_at(idx);
+
+      /* For each bin in this block ... */
+      do
+      {
+	/* Find and use first big enough chunk ... */
+
+	for (victim = last(bin); victim != bin; victim = victim->bk)
+	{
+	  victim_size = chunksize(victim);
+	  remainder_size = victim_size - nb;
+
+	  if (remainder_size >= (long)MINSIZE) /* split */
+	  {
+	    remainder = chunk_at_offset(victim, nb);
+	    set_head(victim, nb | PREV_INUSE);
+	    unlink(victim, bck, fwd);
+	    link_last_remainder(remainder);
+	    set_head(remainder, remainder_size | PREV_INUSE);
+	    set_foot(remainder, remainder_size);
+	    check_malloced_chunk(victim, nb);
+	    return chunk2mem(victim);
+	  }
+
+	  else if (remainder_size >= 0)  /* take */
+	  {
+	    set_inuse_bit_at_offset(victim, victim_size);
+	    unlink(victim, bck, fwd);
+	    check_malloced_chunk(victim, nb);
+	    return chunk2mem(victim);
+	  }
+
+	}
+
+       bin = next_bin(bin);
+
+      } while ((++idx & (BINBLOCKWIDTH - 1)) != 0);
+
+      /* Clear out the block bit. */
+
+      do   /* Possibly backtrack to try to clear a partial block */
+      {
+	if ((startidx & (BINBLOCKWIDTH - 1)) == 0)
+	{
+	  av_[1] = (mbinptr)(binblocks_r & ~block);
+	  break;
+	}
+	--startidx;
+       q = prev_bin(q);
+      } while (first(q) == q);
+
+      /* Get to the next possibly nonempty block */
+
+      if ( (block <<= 1) <= binblocks_r && (block != 0) )
+      {
+	while ((block & binblocks_r) == 0)
+	{
+	  idx += BINBLOCKWIDTH;
+	  block <<= 1;
+	}
+      }
+      else
+	break;
+    }
+  }
+
+
+  /* Try to use top chunk */
+
+  /* Require that there be a remainder, ensuring top always exists  */
+  if ( (remainder_size = chunksize(top) - nb) < (long)MINSIZE)
+  {
+
+#if HAVE_MMAP
+    /* If big and would otherwise need to extend, try to use mmap instead */
+    if ((unsigned long)nb >= (unsigned long)mmap_threshold &&
+	(victim = mmap_chunk(nb)) != 0)
+      return chunk2mem(victim);
+#endif
+
+    /* Try to extend */
+    malloc_extend_top(nb);
+    if ( (remainder_size = chunksize(top) - nb) < (long)MINSIZE)
+      return NULL; /* propagate failure */
+  }
+
+  victim = top;
+  set_head(victim, nb | PREV_INUSE);
+  top = chunk_at_offset(victim, nb);
+  set_head(top, remainder_size | PREV_INUSE);
+  check_malloced_chunk(victim, nb);
+  return chunk2mem(victim);
+
+}
+
+
+
+
+/*
+
+  free() algorithm :
+
+    cases:
+
+       1. free(0) has no effect.
+
+       2. If the chunk was allocated via mmap, it is release via munmap().
+
+       3. If a returned chunk borders the current high end of memory,
+	  it is consolidated into the top, and if the total unused
+	  topmost memory exceeds the trim threshold, malloc_trim is
+	  called.
+
+       4. Other chunks are consolidated as they arrive, and
+	  placed in corresponding bins. (This includes the case of
+	  consolidating with the current `last_remainder').
+
+*/
+
+
+#if __STD_C
+void fREe(Void_t* mem)
+#else
+void fREe(mem) Void_t* mem;
+#endif
+{
+  mchunkptr p;         /* chunk corresponding to mem */
+  INTERNAL_SIZE_T hd;  /* its head field */
+  INTERNAL_SIZE_T sz;  /* its size */
+  int       idx;       /* its bin index */
+  mchunkptr next;      /* next contiguous chunk */
+  INTERNAL_SIZE_T nextsz; /* its size */
+  INTERNAL_SIZE_T prevsz; /* size of previous contiguous chunk */
+  mchunkptr bck;       /* misc temp for linking */
+  mchunkptr fwd;       /* misc temp for linking */
+  int       islr;      /* track whether merging with last_remainder */
+
+  if (mem == NULL)                              /* free(0) has no effect */
+    return;
+
+  p = mem2chunk(mem);
+  hd = p->size;
+
+#if HAVE_MMAP
+  if (hd & IS_MMAPPED)                       /* release mmapped memory. */
+  {
+    munmap_chunk(p);
+    return;
+  }
+#endif
+
+  check_inuse_chunk(p);
+
+  sz = hd & ~PREV_INUSE;
+  next = chunk_at_offset(p, sz);
+  nextsz = chunksize(next);
+
+  if (next == top)                            /* merge with top */
+  {
+    sz += nextsz;
+
+    if (!(hd & PREV_INUSE))                    /* consolidate backward */
+    {
+      prevsz = p->prev_size;
+      p = chunk_at_offset(p, -((long) prevsz));
+      sz += prevsz;
+      unlink(p, bck, fwd);
+    }
+
+    set_head(p, sz | PREV_INUSE);
+    top = p;
+    if ((unsigned long)(sz) >= (unsigned long)trim_threshold)
+      malloc_trim(top_pad);
+    return;
+  }
+
+  set_head(next, nextsz);                    /* clear inuse bit */
+
+  islr = 0;
+
+  if (!(hd & PREV_INUSE))                    /* consolidate backward */
+  {
+    prevsz = p->prev_size;
+    p = chunk_at_offset(p, -((long) prevsz));
+    sz += prevsz;
+
+    if (p->fd == last_remainder)             /* keep as last_remainder */
+      islr = 1;
+    else
+      unlink(p, bck, fwd);
+  }
+
+  if (!(inuse_bit_at_offset(next, nextsz)))   /* consolidate forward */
+  {
+    sz += nextsz;
+
+    if (!islr && next->fd == last_remainder)  /* re-insert last_remainder */
+    {
+      islr = 1;
+      link_last_remainder(p);
+    }
+    else
+      unlink(next, bck, fwd);
+  }
+
+
+  set_head(p, sz | PREV_INUSE);
+  set_foot(p, sz);
+  if (!islr)
+    frontlink(p, sz, idx, bck, fwd);
+}
+
+
+
+
+
+/*
+
+  Realloc algorithm:
+
+    Chunks that were obtained via mmap cannot be extended or shrunk
+    unless HAVE_MREMAP is defined, in which case mremap is used.
+    Otherwise, if their reallocation is for additional space, they are
+    copied.  If for less, they are just left alone.
+
+    Otherwise, if the reallocation is for additional space, and the
+    chunk can be extended, it is, else a malloc-copy-free sequence is
+    taken.  There are several different ways that a chunk could be
+    extended. All are tried:
+
+       * Extending forward into following adjacent free chunk.
+       * Shifting backwards, joining preceding adjacent space
+       * Both shifting backwards and extending forward.
+       * Extending into newly sbrked space
+
+    Unless the #define REALLOC_ZERO_BYTES_FREES is set, realloc with a
+    size argument of zero (re)allocates a minimum-sized chunk.
+
+    If the reallocation is for less space, and the new request is for
+    a `small' (<512 bytes) size, then the newly unused space is lopped
+    off and freed.
+
+    The old unix realloc convention of allowing the last-free'd chunk
+    to be used as an argument to realloc is no longer supported.
+    I don't know of any programs still relying on this feature,
+    and allowing it would also allow too many other incorrect
+    usages of realloc to be sensible.
+
+
+*/
+
+
+#if __STD_C
+Void_t* rEALLOc(Void_t* oldmem, size_t bytes)
+#else
+Void_t* rEALLOc(oldmem, bytes) Void_t* oldmem; size_t bytes;
+#endif
+{
+  INTERNAL_SIZE_T    nb;      /* padded request size */
+
+  mchunkptr oldp;             /* chunk corresponding to oldmem */
+  INTERNAL_SIZE_T    oldsize; /* its size */
+
+  mchunkptr newp;             /* chunk to return */
+  INTERNAL_SIZE_T    newsize; /* its size */
+  Void_t*   newmem;           /* corresponding user mem */
+
+  mchunkptr next;             /* next contiguous chunk after oldp */
+  INTERNAL_SIZE_T  nextsize;  /* its size */
+
+  mchunkptr prev;             /* previous contiguous chunk before oldp */
+  INTERNAL_SIZE_T  prevsize;  /* its size */
+
+  mchunkptr remainder;        /* holds split off extra space from newp */
+  INTERNAL_SIZE_T  remainder_size;   /* its size */
+
+  mchunkptr bck;              /* misc temp for linking */
+  mchunkptr fwd;              /* misc temp for linking */
+
+#ifdef REALLOC_ZERO_BYTES_FREES
+  if (bytes == 0) { fREe(oldmem); return 0; }
+#endif
+
+  if ((long)bytes < 0) return NULL;
+
+  /* realloc of null is supposed to be same as malloc */
+  if (oldmem == NULL) return mALLOc(bytes);
+
+  newp    = oldp    = mem2chunk(oldmem);
+  newsize = oldsize = chunksize(oldp);
+
+
+  nb = request2size(bytes);
+
+#if HAVE_MMAP
+  if (chunk_is_mmapped(oldp))
+  {
+#if HAVE_MREMAP
+    newp = mremap_chunk(oldp, nb);
+    if(newp) return chunk2mem(newp);
+#endif
+    /* Note the extra SIZE_SZ overhead. */
+    if(oldsize - SIZE_SZ >= nb) return oldmem; /* do nothing */
+    /* Must alloc, copy, free. */
+    newmem = mALLOc(bytes);
+    if (newmem == 0) return 0; /* propagate failure */
+    MALLOC_COPY(newmem, oldmem, oldsize - 2*SIZE_SZ);
+    munmap_chunk(oldp);
+    return newmem;
+  }
+#endif
+
+  check_inuse_chunk(oldp);
+
+  if ((long)(oldsize) < (long)(nb))
+  {
+
+    /* Try expanding forward */
+
+    next = chunk_at_offset(oldp, oldsize);
+    if (next == top || !inuse(next))
+    {
+      nextsize = chunksize(next);
+
+      /* Forward into top only if a remainder */
+      if (next == top)
+      {
+	if ((long)(nextsize + newsize) >= (long)(nb + MINSIZE))
+	{
+	  newsize += nextsize;
+	  top = chunk_at_offset(oldp, nb);
+	  set_head(top, (newsize - nb) | PREV_INUSE);
+	  set_head_size(oldp, nb);
+	  return chunk2mem(oldp);
+	}
+      }
+
+      /* Forward into next chunk */
+      else if (((long)(nextsize + newsize) >= (long)(nb)))
+      {
+	unlink(next, bck, fwd);
+	newsize  += nextsize;
+	goto split;
+      }
+    }
+    else
+    {
+      next = NULL;
+      nextsize = 0;
+    }
+
+    /* Try shifting backwards. */
+
+    if (!prev_inuse(oldp))
+    {
+      prev = prev_chunk(oldp);
+      prevsize = chunksize(prev);
+
+      /* try forward + backward first to save a later consolidation */
+
+      if (next != NULL)
+      {
+	/* into top */
+	if (next == top)
+	{
+	  if ((long)(nextsize + prevsize + newsize) >= (long)(nb + MINSIZE))
+	  {
+	    unlink(prev, bck, fwd);
+	    newp = prev;
+	    newsize += prevsize + nextsize;
+	    newmem = chunk2mem(newp);
+	    MALLOC_COPY(newmem, oldmem, oldsize - SIZE_SZ);
+	    top = chunk_at_offset(newp, nb);
+	    set_head(top, (newsize - nb) | PREV_INUSE);
+	    set_head_size(newp, nb);
+	    return newmem;
+	  }
+	}
+
+	/* into next chunk */
+	else if (((long)(nextsize + prevsize + newsize) >= (long)(nb)))
+	{
+	  unlink(next, bck, fwd);
+	  unlink(prev, bck, fwd);
+	  newp = prev;
+	  newsize += nextsize + prevsize;
+	  newmem = chunk2mem(newp);
+	  MALLOC_COPY(newmem, oldmem, oldsize - SIZE_SZ);
+	  goto split;
+	}
+      }
+
+      /* backward only */
+      if (prev != NULL && (long)(prevsize + newsize) >= (long)nb)
+      {
+	unlink(prev, bck, fwd);
+	newp = prev;
+	newsize += prevsize;
+	newmem = chunk2mem(newp);
+	MALLOC_COPY(newmem, oldmem, oldsize - SIZE_SZ);
+	goto split;
+      }
+    }
+
+    /* Must allocate */
+
+    newmem = mALLOc (bytes);
+
+    if (newmem == NULL)  /* propagate failure */
+      return NULL;
+
+    /* Avoid copy if newp is next chunk after oldp. */
+    /* (This can only happen when new chunk is sbrk'ed.) */
+
+    if ( (newp = mem2chunk(newmem)) == next_chunk(oldp))
+    {
+      newsize += chunksize(newp);
+      newp = oldp;
+      goto split;
+    }
+
+    /* Otherwise copy, free, and exit */
+    MALLOC_COPY(newmem, oldmem, oldsize - SIZE_SZ);
+    fREe(oldmem);
+    return newmem;
+  }
+
+
+ split:  /* split off extra room in old or expanded chunk */
+
+  if (newsize - nb >= MINSIZE) /* split off remainder */
+  {
+    remainder = chunk_at_offset(newp, nb);
+    remainder_size = newsize - nb;
+    set_head_size(newp, nb);
+    set_head(remainder, remainder_size | PREV_INUSE);
+    set_inuse_bit_at_offset(remainder, remainder_size);
+    fREe(chunk2mem(remainder)); /* let free() deal with it */
+  }
+  else
+  {
+    set_head_size(newp, newsize);
+    set_inuse_bit_at_offset(newp, newsize);
+  }
+
+  check_inuse_chunk(newp);
+  return chunk2mem(newp);
+}
+
+
+
+
+/*
+
+  memalign algorithm:
+
+    memalign requests more than enough space from malloc, finds a spot
+    within that chunk that meets the alignment request, and then
+    possibly frees the leading and trailing space.
+
+    The alignment argument must be a power of two. This property is not
+    checked by memalign, so misuse may result in random runtime errors.
+
+    8-byte alignment is guaranteed by normal malloc calls, so don't
+    bother calling memalign with an argument of 8 or less.
+
+    Overreliance on memalign is a sure way to fragment space.
+
+*/
+
+
+#if __STD_C
+Void_t* mEMALIGn(size_t alignment, size_t bytes)
+#else
+Void_t* mEMALIGn(alignment, bytes) size_t alignment; size_t bytes;
+#endif
+{
+  INTERNAL_SIZE_T    nb;      /* padded  request size */
+  char*     m;                /* memory returned by malloc call */
+  mchunkptr p;                /* corresponding chunk */
+  char*     brk;              /* alignment point within p */
+  mchunkptr newp;             /* chunk to return */
+  INTERNAL_SIZE_T  newsize;   /* its size */
+  INTERNAL_SIZE_T  leadsize;  /* leading space befor alignment point */
+  mchunkptr remainder;        /* spare room at end to split off */
+  long      remainder_size;   /* its size */
+
+  if ((long)bytes < 0) return NULL;
+
+  /* If need less alignment than we give anyway, just relay to malloc */
+
+  if (alignment <= MALLOC_ALIGNMENT) return mALLOc(bytes);
+
+  /* Otherwise, ensure that it is at least a minimum chunk size */
+
+  if (alignment <  MINSIZE) alignment = MINSIZE;
+
+  /* Call malloc with worst case padding to hit alignment. */
+
+  nb = request2size(bytes);
+  m  = (char*)(mALLOc(nb + alignment + MINSIZE));
+
+  if (m == NULL) return NULL; /* propagate failure */
+
+  p = mem2chunk(m);
+
+  if ((((unsigned long)(m)) % alignment) == 0) /* aligned */
+  {
+#if HAVE_MMAP
+    if(chunk_is_mmapped(p))
+      return chunk2mem(p); /* nothing more to do */
+#endif
+  }
+  else /* misaligned */
+  {
+    /*
+      Find an aligned spot inside chunk.
+      Since we need to give back leading space in a chunk of at
+      least MINSIZE, if the first calculation places us at
+      a spot with less than MINSIZE leader, we can move to the
+      next aligned spot -- we've allocated enough total room so that
+      this is always possible.
+    */
+
+    brk = (char*)mem2chunk(((unsigned long)(m + alignment - 1)) & -((signed) alignment));
+    if ((long)(brk - (char*)(p)) < MINSIZE) brk = brk + alignment;
+
+    newp = (mchunkptr)brk;
+    leadsize = brk - (char*)(p);
+    newsize = chunksize(p) - leadsize;
+
+#if HAVE_MMAP
+    if(chunk_is_mmapped(p))
+    {
+      newp->prev_size = p->prev_size + leadsize;
+      set_head(newp, newsize|IS_MMAPPED);
+      return chunk2mem(newp);
+    }
+#endif
+
+    /* give back leader, use the rest */
+
+    set_head(newp, newsize | PREV_INUSE);
+    set_inuse_bit_at_offset(newp, newsize);
+    set_head_size(p, leadsize);
+    fREe(chunk2mem(p));
+    p = newp;
+
+    assert (newsize >= nb && (((unsigned long)(chunk2mem(p))) % alignment) == 0);
+  }
+
+  /* Also give back spare room at the end */
+
+  remainder_size = chunksize(p) - nb;
+
+  if (remainder_size >= (long)MINSIZE)
+  {
+    remainder = chunk_at_offset(p, nb);
+    set_head(remainder, remainder_size | PREV_INUSE);
+    set_head_size(p, nb);
+    fREe(chunk2mem(remainder));
+  }
+
+  check_inuse_chunk(p);
+  return chunk2mem(p);
+
+}
+
+
+
+
+/*
+    valloc just invokes memalign with alignment argument equal
+    to the page size of the system (or as near to this as can
+    be figured out from all the includes/defines above.)
+*/
+
+#if __STD_C
+Void_t* vALLOc(size_t bytes)
+#else
+Void_t* vALLOc(bytes) size_t bytes;
+#endif
+{
+  return mEMALIGn (malloc_getpagesize, bytes);
+}
+
+/*
+  pvalloc just invokes valloc for the nearest pagesize
+  that will accommodate request
+*/
+
+
+#if __STD_C
+Void_t* pvALLOc(size_t bytes)
+#else
+Void_t* pvALLOc(bytes) size_t bytes;
+#endif
+{
+  size_t pagesize = malloc_getpagesize;
+  return mEMALIGn (pagesize, (bytes + pagesize - 1) & ~(pagesize - 1));
+}
+
+/*
+
+  calloc calls malloc, then zeroes out the allocated chunk.
+
+*/
+
+#if __STD_C
+Void_t* cALLOc(size_t n, size_t elem_size)
+#else
+Void_t* cALLOc(n, elem_size) size_t n; size_t elem_size;
+#endif
+{
+  mchunkptr p;
+  INTERNAL_SIZE_T csz;
+
+  INTERNAL_SIZE_T sz = n * elem_size;
+
+
+  /* check if expand_top called, in which case don't need to clear */
+#if MORECORE_CLEARS
+  mchunkptr oldtop = top;
+  INTERNAL_SIZE_T oldtopsize = chunksize(top);
+#endif
+  Void_t* mem = mALLOc (sz);
+
+  if ((long)n < 0) return NULL;
+
+  if (mem == NULL)
+    return NULL;
+  else
+  {
+    p = mem2chunk(mem);
+
+    /* Two optional cases in which clearing not necessary */
+
+
+#if HAVE_MMAP
+    if (chunk_is_mmapped(p)) return mem;
+#endif
+
+    csz = chunksize(p);
+
+#if MORECORE_CLEARS
+    if (p == oldtop && csz > oldtopsize)
+    {
+      /* clear only the bytes from non-freshly-sbrked memory */
+      csz = oldtopsize;
+    }
+#endif
+
+    MALLOC_ZERO(mem, csz - SIZE_SZ);
+    return mem;
+  }
+}
+
+/*
+
+  cfree just calls free. It is needed/defined on some systems
+  that pair it with calloc, presumably for odd historical reasons.
+
+*/
+
+#if !defined(INTERNAL_LINUX_C_LIB) || !defined(__ELF__)
+#if __STD_C
+void cfree(Void_t *mem)
+#else
+void cfree(mem) Void_t *mem;
+#endif
+{
+  fREe(mem);
+}
+#endif
+
+
+
+/*
+
+    Malloc_trim gives memory back to the system (via negative
+    arguments to sbrk) if there is unused memory at the `high' end of
+    the malloc pool. You can call this after freeing large blocks of
+    memory to potentially reduce the system-level memory requirements
+    of a program. However, it cannot guarantee to reduce memory. Under
+    some allocation patterns, some large free blocks of memory will be
+    locked between two used chunks, so they cannot be given back to
+    the system.
+
+    The `pad' argument to malloc_trim represents the amount of free
+    trailing space to leave untrimmed. If this argument is zero,
+    only the minimum amount of memory to maintain internal data
+    structures will be left (one page or less). Non-zero arguments
+    can be supplied to maintain enough trailing space to service
+    future expected allocations without having to re-obtain memory
+    from the system.
+
+    Malloc_trim returns 1 if it actually released any memory, else 0.
+
+*/
+
+#if __STD_C
+int malloc_trim(size_t pad)
+#else
+int malloc_trim(pad) size_t pad;
+#endif
+{
+  long  top_size;        /* Amount of top-most memory */
+  long  extra;           /* Amount to release */
+  char* current_brk;     /* address returned by pre-check sbrk call */
+  char* new_brk;         /* address returned by negative sbrk call */
+
+  unsigned long pagesz = malloc_getpagesize;
+
+  top_size = chunksize(top);
+  extra = ((top_size - pad - MINSIZE + (pagesz-1)) / pagesz - 1) * pagesz;
+
+  if (extra < (long)pagesz)  /* Not enough memory to release */
+    return 0;
+
+  else
+  {
+    /* Test to make sure no one else called sbrk */
+    current_brk = (char*)(MORECORE (0));
+    if (current_brk != (char*)(top) + top_size)
+      return 0;     /* Apparently we don't own memory; must fail */
+
+    else
+    {
+      new_brk = (char*)(MORECORE (-extra));
+
+      if (new_brk == (char*)(MORECORE_FAILURE)) /* sbrk failed? */
+      {
+	/* Try to figure out what we have */
+	current_brk = (char*)(MORECORE (0));
+	top_size = current_brk - (char*)top;
+	if (top_size >= (long)MINSIZE) /* if not, we are very very dead! */
+	{
+	  sbrked_mem = current_brk - sbrk_base;
+	  set_head(top, top_size | PREV_INUSE);
+	}
+	check_chunk(top);
+	return 0;
+      }
+
+      else
+      {
+	/* Success. Adjust top accordingly. */
+	set_head(top, (top_size - extra) | PREV_INUSE);
+	sbrked_mem -= extra;
+	check_chunk(top);
+	return 1;
+      }
+    }
+  }
+}
+
+
+
+/*
+  malloc_usable_size:
+
+    This routine tells you how many bytes you can actually use in an
+    allocated chunk, which may be more than you requested (although
+    often not). You can use this many bytes without worrying about
+    overwriting other allocated objects. Not a particularly great
+    programming practice, but still sometimes useful.
+
+*/
+
+#if __STD_C
+size_t malloc_usable_size(Void_t* mem)
+#else
+size_t malloc_usable_size(mem) Void_t* mem;
+#endif
+{
+  mchunkptr p;
+  if (mem == NULL)
+    return 0;
+  else
+  {
+    p = mem2chunk(mem);
+    if(!chunk_is_mmapped(p))
+    {
+      if (!inuse(p)) return 0;
+      check_inuse_chunk(p);
+      return chunksize(p) - SIZE_SZ;
+    }
+    return chunksize(p) - 2*SIZE_SZ;
+  }
+}
+
+
+
+
+/* Utility to update current_mallinfo for malloc_stats and mallinfo() */
+
+#ifdef DEBUG
+static void malloc_update_mallinfo()
+{
+  int i;
+  mbinptr b;
+  mchunkptr p;
+#ifdef DEBUG
+  mchunkptr q;
+#endif
+
+  INTERNAL_SIZE_T avail = chunksize(top);
+  int   navail = ((long)(avail) >= (long)MINSIZE)? 1 : 0;
+
+  for (i = 1; i < NAV; ++i)
+  {
+    b = bin_at(i);
+    for (p = last(b); p != b; p = p->bk)
+    {
+#ifdef DEBUG
+      check_free_chunk(p);
+      for (q = next_chunk(p);
+	   q < top && inuse(q) && (long)(chunksize(q)) >= (long)MINSIZE;
+	   q = next_chunk(q))
+	check_inuse_chunk(q);
+#endif
+      avail += chunksize(p);
+      navail++;
+    }
+  }
+
+  current_mallinfo.ordblks = navail;
+  current_mallinfo.uordblks = sbrked_mem - avail;
+  current_mallinfo.fordblks = avail;
+  current_mallinfo.hblks = n_mmaps;
+  current_mallinfo.hblkhd = mmapped_mem;
+  current_mallinfo.keepcost = chunksize(top);
+
+}
+#endif	/* DEBUG */
+
+
+
+/*
+
+  malloc_stats:
+
+    Prints on the amount of space obtain from the system (both
+    via sbrk and mmap), the maximum amount (which may be more than
+    current if malloc_trim and/or munmap got called), the maximum
+    number of simultaneous mmap regions used, and the current number
+    of bytes allocated via malloc (or realloc, etc) but not yet
+    freed. (Note that this is the number of bytes allocated, not the
+    number requested. It will be larger than the number requested
+    because of alignment and bookkeeping overhead.)
+
+*/
+
+#ifdef DEBUG
+void malloc_stats()
+{
+  malloc_update_mallinfo();
+  printf("max system bytes = %10u\n",
+	  (unsigned int)(max_total_mem));
+  printf("system bytes     = %10u\n",
+	  (unsigned int)(sbrked_mem + mmapped_mem));
+  printf("in use bytes     = %10u\n",
+	  (unsigned int)(current_mallinfo.uordblks + mmapped_mem));
+#if HAVE_MMAP
+  printf("max mmap regions = %10u\n",
+	  (unsigned int)max_n_mmaps);
+#endif
+}
+#endif	/* DEBUG */
+
+/*
+  mallinfo returns a copy of updated current mallinfo.
+*/
+
+#ifdef DEBUG
+struct mallinfo mALLINFo()
+{
+  malloc_update_mallinfo();
+  return current_mallinfo;
+}
+#endif	/* DEBUG */
+
+
+
+
+/*
+  mallopt:
+
+    mallopt is the general SVID/XPG interface to tunable parameters.
+    The format is to provide a (parameter-number, parameter-value) pair.
+    mallopt then sets the corresponding parameter to the argument
+    value if it can (i.e., so long as the value is meaningful),
+    and returns 1 if successful else 0.
+
+    See descriptions of tunable parameters above.
+
+*/
+
+#if __STD_C
+int mALLOPt(int param_number, int value)
+#else
+int mALLOPt(param_number, value) int param_number; int value;
+#endif
+{
+  switch(param_number)
+  {
+    case M_TRIM_THRESHOLD:
+      trim_threshold = value; return 1;
+    case M_TOP_PAD:
+      top_pad = value; return 1;
+    case M_MMAP_THRESHOLD:
+      mmap_threshold = value; return 1;
+    case M_MMAP_MAX:
+#if HAVE_MMAP
+      n_mmaps_max = value; return 1;
+#else
+      if (value != 0) return 0; else  n_mmaps_max = value; return 1;
+#endif
+
+    default:
+      return 0;
+  }
+}
+
+/*
+
+History:
+
+    V2.6.6 Sun Dec  5 07:42:19 1999  Doug Lea  (dl at gee)
+      * return null for negative arguments
+      * Added Several WIN32 cleanups from Martin C. Fong <mcfong@yahoo.com>
+	 * Add 'LACKS_SYS_PARAM_H' for those systems without 'sys/param.h'
+	  (e.g. WIN32 platforms)
+	 * Cleanup up header file inclusion for WIN32 platforms
+	 * Cleanup code to avoid Microsoft Visual C++ compiler complaints
+	 * Add 'USE_DL_PREFIX' to quickly allow co-existence with existing
+	   memory allocation routines
+	 * Set 'malloc_getpagesize' for WIN32 platforms (needs more work)
+	 * Use 'assert' rather than 'ASSERT' in WIN32 code to conform to
+	   usage of 'assert' in non-WIN32 code
+	 * Improve WIN32 'sbrk()' emulation's 'findRegion()' routine to
+	   avoid infinite loop
+      * Always call 'fREe()' rather than 'free()'
+
+    V2.6.5 Wed Jun 17 15:57:31 1998  Doug Lea  (dl at gee)
+      * Fixed ordering problem with boundary-stamping
+
+    V2.6.3 Sun May 19 08:17:58 1996  Doug Lea  (dl at gee)
+      * Added pvalloc, as recommended by H.J. Liu
+      * Added 64bit pointer support mainly from Wolfram Gloger
+      * Added anonymously donated WIN32 sbrk emulation
+      * Malloc, calloc, getpagesize: add optimizations from Raymond Nijssen
+      * malloc_extend_top: fix mask error that caused wastage after
+	foreign sbrks
+      * Add linux mremap support code from HJ Liu
+
+    V2.6.2 Tue Dec  5 06:52:55 1995  Doug Lea  (dl at gee)
+      * Integrated most documentation with the code.
+      * Add support for mmap, with help from
+	Wolfram Gloger (Gloger@lrz.uni-muenchen.de).
+      * Use last_remainder in more cases.
+      * Pack bins using idea from  colin@nyx10.cs.du.edu
+      * Use ordered bins instead of best-fit threshhold
+      * Eliminate block-local decls to simplify tracing and debugging.
+      * Support another case of realloc via move into top
+      * Fix error occuring when initial sbrk_base not word-aligned.
+      * Rely on page size for units instead of SBRK_UNIT to
+	avoid surprises about sbrk alignment conventions.
+      * Add mallinfo, mallopt. Thanks to Raymond Nijssen
+	(raymond@es.ele.tue.nl) for the suggestion.
+      * Add `pad' argument to malloc_trim and top_pad mallopt parameter.
+      * More precautions for cases where other routines call sbrk,
+	courtesy of Wolfram Gloger (Gloger@lrz.uni-muenchen.de).
+      * Added macros etc., allowing use in linux libc from
+	H.J. Lu (hjl@gnu.ai.mit.edu)
+      * Inverted this history list
+
+    V2.6.1 Sat Dec  2 14:10:57 1995  Doug Lea  (dl at gee)
+      * Re-tuned and fixed to behave more nicely with V2.6.0 changes.
+      * Removed all preallocation code since under current scheme
+	the work required to undo bad preallocations exceeds
+	the work saved in good cases for most test programs.
+      * No longer use return list or unconsolidated bins since
+	no scheme using them consistently outperforms those that don't
+	given above changes.
+      * Use best fit for very large chunks to prevent some worst-cases.
+      * Added some support for debugging
+
+    V2.6.0 Sat Nov  4 07:05:23 1995  Doug Lea  (dl at gee)
+      * Removed footers when chunks are in use. Thanks to
+	Paul Wilson (wilson@cs.texas.edu) for the suggestion.
+
+    V2.5.4 Wed Nov  1 07:54:51 1995  Doug Lea  (dl at gee)
+      * Added malloc_trim, with help from Wolfram Gloger
+	(wmglo@Dent.MED.Uni-Muenchen.DE).
+
+    V2.5.3 Tue Apr 26 10:16:01 1994  Doug Lea  (dl at g)
+
+    V2.5.2 Tue Apr  5 16:20:40 1994  Doug Lea  (dl at g)
+      * realloc: try to expand in both directions
+      * malloc: swap order of clean-bin strategy;
+      * realloc: only conditionally expand backwards
+      * Try not to scavenge used bins
+      * Use bin counts as a guide to preallocation
+      * Occasionally bin return list chunks in first scan
+      * Add a few optimizations from colin@nyx10.cs.du.edu
+
+    V2.5.1 Sat Aug 14 15:40:43 1993  Doug Lea  (dl at g)
+      * faster bin computation & slightly different binning
+      * merged all consolidations to one part of malloc proper
+	 (eliminating old malloc_find_space & malloc_clean_bin)
+      * Scan 2 returns chunks (not just 1)
+      * Propagate failure in realloc if malloc returns 0
+      * Add stuff to allow compilation on non-ANSI compilers
+	  from kpv@research.att.com
+
+    V2.5 Sat Aug  7 07:41:59 1993  Doug Lea  (dl at g.oswego.edu)
+      * removed potential for odd address access in prev_chunk
+      * removed dependency on getpagesize.h
+      * misc cosmetics and a bit more internal documentation
+      * anticosmetics: mangled names in macros to evade debugger strangeness
+      * tested on sparc, hp-700, dec-mips, rs6000
+	  with gcc & native cc (hp, dec only) allowing
+	  Detlefs & Zorn comparison study (in SIGPLAN Notices.)
+
+    Trial version Fri Aug 28 13:14:29 1992  Doug Lea  (dl at g.oswego.edu)
+      * Based loosely on libg++-1.2X malloc. (It retains some of the overall
+	 structure of old version,  but most details differ.)
+
+*/
diff --git a/linux-bsp/asm-study/yaffs2/common/makefile b/linux-bsp/asm-study/yaffs2/common/makefile
new file mode 100644
index 0000000..78e9641
--- /dev/null
+++ b/linux-bsp/asm-study/yaffs2/common/makefile
@@ -0,0 +1,97 @@
+#*********************************************************************************
+#      Copyright:  (C) 2012 CoherentPlus Sdn. Bhd.
+#                  All rights reserved.
+#
+#       Filename:  Makefile
+#    Description:  This is the common subdir Makefile which to compile all the C
+#                  source code to object files and then generate the shared or 
+#                  static library named lib$(FOLDER_NAME).a orlib $(FOLDER_NAME).so,
+#                  which depends on the variable $LINK_MODE.
+#                      
+#        Version:  1.0.0(10/08/2011~)
+#                  Author:  Guo Wenxue <guowenxue@gmail.com>
+#      ChangeLog:  1, Release initial version on "10/08/2011 01:29:33 AM"
+#                       
+#********************************************************************************/
+
+PWD=$(shell pwd)
+LOCAL_COMPILE=YES
+LINK_MODE=STATIC
+
+#If wanna compile in the subdir, not called by top makefile, uncomment it
+ifneq (${TOP_COMPILE}, YES) 
+LOCAL_COMPILE=YES
+endif
+
+LIBNAME=$(shell basename ${PWD})
+STALIB=lib${LIBNAME}.a
+DYNLIB=lib${LIBNAME}.so
+
+VPATH= .
+SRCS = $(wildcard ${VPATH}/*.c)
+OBJS = $(patsubst %.c,%.o,$(SRCS))
+
+#======================================================
+#  ---> Doesn't call by top makefile, compile by local
+#======================================================
+ifeq (${LOCAL_COMPILE}, YES)
+ARCH?=arm920t
+#ARCH?=i386
+CFLAGS+=-fPIC
+TMP=$(shell echo $(ARCH) | tr "[A-Z]" "[a-z]")
+ifneq (,$(filter i386,$(TMP)))
+    CROSS_COMPILE=
+else
+    CROSS_COMPILE=/opt/xtools/arm920t/bin/arm-linux-
+endif
+
+PRJDIR?=$(shell pwd)
+CFLAGS+=-I${PRJDIR}
+CC = ${CROSS_COMPILE}gcc
+AR = ${CROSS_COMPILE}ar
+
+endif #End local compile
+
+ifeq ("${LINK_MODE}", "STATIC")
+	LIBS = ${STALIB} 
+else 
+	LIBS=${DYNLIB}
+endif
+
+all: entry ${LIBS} install
+
+entry: 
+	@echo " ";
+	@echo " =========================================================";
+	@echo " **     Compile subdir ${LIBNAME} for ${ARCH}             ";
+	@echo " =========================================================";
+
+#$(LD) -g --relocatable $(OBJS) -o lib${LIBNAME}.o
+${STALIB}:	$(OBJS) 
+	$(AR) -rcu $@ $(OBJS)
+
+${DYNLIB}:   $(OBJS) 
+	$(CC) -fPIC -shared -o $@ $(OBJS)
+
+%.o : %.c
+	$(CC) -c $< $(CFLAGS)
+
+tag: 
+	@ctags --c-kinds=+defglmnstuvx --langmap=c:.c.h.ho.hem.het.hec.hev.him.hit.hic.hiv -R .  
+	@cscope -Rbq
+
+install:
+	@if [ ! -z "${LIBS_PATH}" ] ; then \
+		mkdir -p ${LIBS_PATH} ; \
+		cp ${LIBS} ${LIBS_PATH}; \
+	fi;
+
+
+clean:
+	@rm -f *.o
+	@rm -rf *.gdb *.a *.so
+
+distclean: clean
+	@rm -f  tags cscope*
+
+.PHONY: clean entry
diff --git a/linux-bsp/asm-study/yaffs2/common/malloc.h b/linux-bsp/asm-study/yaffs2/common/malloc.h
new file mode 100644
index 0000000..319438a
--- /dev/null
+++ b/linux-bsp/asm-study/yaffs2/common/malloc.h
@@ -0,0 +1,947 @@
+/*
+  A version of malloc/free/realloc written by Doug Lea and released to the
+  public domain.  Send questions/comments/complaints/performance data
+  to dl@cs.oswego.edu
+
+* VERSION 2.6.6  Sun Mar  5 19:10:03 2000  Doug Lea  (dl at gee)
+
+   Note: There may be an updated version of this malloc obtainable at
+	   ftp://g.oswego.edu/pub/misc/malloc.c
+	 Check before installing!
+
+* Why use this malloc?
+
+  This is not the fastest, most space-conserving, most portable, or
+  most tunable malloc ever written. However it is among the fastest
+  while also being among the most space-conserving, portable and tunable.
+  Consistent balance across these factors results in a good general-purpose
+  allocator. For a high-level description, see
+     http://g.oswego.edu/dl/html/malloc.html
+
+* Synopsis of public routines
+
+  (Much fuller descriptions are contained in the program documentation below.)
+
+  malloc(size_t n);
+     Return a pointer to a newly allocated chunk of at least n bytes, or null
+     if no space is available.
+  free(Void_t* p);
+     Release the chunk of memory pointed to by p, or no effect if p is null.
+  realloc(Void_t* p, size_t n);
+     Return a pointer to a chunk of size n that contains the same data
+     as does chunk p up to the minimum of (n, p's size) bytes, or null
+     if no space is available. The returned pointer may or may not be
+     the same as p. If p is null, equivalent to malloc.  Unless the
+     #define REALLOC_ZERO_BYTES_FREES below is set, realloc with a
+     size argument of zero (re)allocates a minimum-sized chunk.
+  memalign(size_t alignment, size_t n);
+     Return a pointer to a newly allocated chunk of n bytes, aligned
+     in accord with the alignment argument, which must be a power of
+     two.
+  valloc(size_t n);
+     Equivalent to memalign(pagesize, n), where pagesize is the page
+     size of the system (or as near to this as can be figured out from
+     all the includes/defines below.)
+  pvalloc(size_t n);
+     Equivalent to valloc(minimum-page-that-holds(n)), that is,
+     round up n to nearest pagesize.
+  calloc(size_t unit, size_t quantity);
+     Returns a pointer to quantity * unit bytes, with all locations
+     set to zero.
+  cfree(Void_t* p);
+     Equivalent to free(p).
+  malloc_trim(size_t pad);
+     Release all but pad bytes of freed top-most memory back
+     to the system. Return 1 if successful, else 0.
+  malloc_usable_size(Void_t* p);
+     Report the number usable allocated bytes associated with allocated
+     chunk p. This may or may not report more bytes than were requested,
+     due to alignment and minimum size constraints.
+  malloc_stats();
+     Prints brief summary statistics on stderr.
+  mallinfo()
+     Returns (by copy) a struct containing various summary statistics.
+  mallopt(int parameter_number, int parameter_value)
+     Changes one of the tunable parameters described below. Returns
+     1 if successful in changing the parameter, else 0.
+
+* Vital statistics:
+
+  Alignment:                            8-byte
+       8 byte alignment is currently hardwired into the design.  This
+       seems to suffice for all current machines and C compilers.
+
+  Assumed pointer representation:       4 or 8 bytes
+       Code for 8-byte pointers is untested by me but has worked
+       reliably by Wolfram Gloger, who contributed most of the
+       changes supporting this.
+
+  Assumed size_t  representation:       4 or 8 bytes
+       Note that size_t is allowed to be 4 bytes even if pointers are 8.
+
+  Minimum overhead per allocated chunk: 4 or 8 bytes
+       Each malloced chunk has a hidden overhead of 4 bytes holding size
+       and status information.
+
+  Minimum allocated size: 4-byte ptrs:  16 bytes    (including 4 overhead)
+			  8-byte ptrs:  24/32 bytes (including, 4/8 overhead)
+
+       When a chunk is freed, 12 (for 4byte ptrs) or 20 (for 8 byte
+       ptrs but 4 byte size) or 24 (for 8/8) additional bytes are
+       needed; 4 (8) for a trailing size field
+       and 8 (16) bytes for free list pointers. Thus, the minimum
+       allocatable size is 16/24/32 bytes.
+
+       Even a request for zero bytes (i.e., malloc(0)) returns a
+       pointer to something of the minimum allocatable size.
+
+  Maximum allocated size: 4-byte size_t: 2^31 -  8 bytes
+			  8-byte size_t: 2^63 - 16 bytes
+
+       It is assumed that (possibly signed) size_t bit values suffice to
+       represent chunk sizes. `Possibly signed' is due to the fact
+       that `size_t' may be defined on a system as either a signed or
+       an unsigned type. To be conservative, values that would appear
+       as negative numbers are avoided.
+       Requests for sizes with a negative sign bit when the request
+       size is treaded as a long will return null.
+
+  Maximum overhead wastage per allocated chunk: normally 15 bytes
+
+       Alignnment demands, plus the minimum allocatable size restriction
+       make the normal worst-case wastage 15 bytes (i.e., up to 15
+       more bytes will be allocated than were requested in malloc), with
+       two exceptions:
+	 1. Because requests for zero bytes allocate non-zero space,
+	    the worst case wastage for a request of zero bytes is 24 bytes.
+	 2. For requests >= mmap_threshold that are serviced via
+	    mmap(), the worst case wastage is 8 bytes plus the remainder
+	    from a system page (the minimal mmap unit); typically 4096 bytes.
+
+* Limitations
+
+    Here are some features that are NOT currently supported
+
+    * No user-definable hooks for callbacks and the like.
+    * No automated mechanism for fully checking that all accesses
+      to malloced memory stay within their bounds.
+    * No support for compaction.
+
+* Synopsis of compile-time options:
+
+    People have reported using previous versions of this malloc on all
+    versions of Unix, sometimes by tweaking some of the defines
+    below. It has been tested most extensively on Solaris and
+    Linux. It is also reported to work on WIN32 platforms.
+    People have also reported adapting this malloc for use in
+    stand-alone embedded systems.
+
+    The implementation is in straight, hand-tuned ANSI C.  Among other
+    consequences, it uses a lot of macros.  Because of this, to be at
+    all usable, this code should be compiled using an optimizing compiler
+    (for example gcc -O2) that can simplify expressions and control
+    paths.
+
+  __STD_C                  (default: derived from C compiler defines)
+     Nonzero if using ANSI-standard C compiler, a C++ compiler, or
+     a C compiler sufficiently close to ANSI to get away with it.
+  DEBUG                    (default: NOT defined)
+     Define to enable debugging. Adds fairly extensive assertion-based
+     checking to help track down memory errors, but noticeably slows down
+     execution.
+  REALLOC_ZERO_BYTES_FREES (default: NOT defined)
+     Define this if you think that realloc(p, 0) should be equivalent
+     to free(p). Otherwise, since malloc returns a unique pointer for
+     malloc(0), so does realloc(p, 0).
+  HAVE_MEMCPY               (default: defined)
+     Define if you are not otherwise using ANSI STD C, but still
+     have memcpy and memset in your C library and want to use them.
+     Otherwise, simple internal versions are supplied.
+  USE_MEMCPY               (default: 1 if HAVE_MEMCPY is defined, 0 otherwise)
+     Define as 1 if you want the C library versions of memset and
+     memcpy called in realloc and calloc (otherwise macro versions are used).
+     At least on some platforms, the simple macro versions usually
+     outperform libc versions.
+  HAVE_MMAP                 (default: defined as 1)
+     Define to non-zero to optionally make malloc() use mmap() to
+     allocate very large blocks.
+  HAVE_MREMAP                 (default: defined as 0 unless Linux libc set)
+     Define to non-zero to optionally make realloc() use mremap() to
+     reallocate very large blocks.
+  malloc_getpagesize        (default: derived from system #includes)
+     Either a constant or routine call returning the system page size.
+  HAVE_USR_INCLUDE_MALLOC_H (default: NOT defined)
+     Optionally define if you are on a system with a /usr/include/malloc.h
+     that declares struct mallinfo. It is not at all necessary to
+     define this even if you do, but will ensure consistency.
+  INTERNAL_SIZE_T           (default: size_t)
+     Define to a 32-bit type (probably `unsigned int') if you are on a
+     64-bit machine, yet do not want or need to allow malloc requests of
+     greater than 2^31 to be handled. This saves space, especially for
+     very small chunks.
+  INTERNAL_LINUX_C_LIB      (default: NOT defined)
+     Defined only when compiled as part of Linux libc.
+     Also note that there is some odd internal name-mangling via defines
+     (for example, internally, `malloc' is named `mALLOc') needed
+     when compiling in this case. These look funny but don't otherwise
+     affect anything.
+  WIN32                     (default: undefined)
+     Define this on MS win (95, nt) platforms to compile in sbrk emulation.
+  LACKS_UNISTD_H            (default: undefined if not WIN32)
+     Define this if your system does not have a <unistd.h>.
+  LACKS_SYS_PARAM_H         (default: undefined if not WIN32)
+     Define this if your system does not have a <sys/param.h>.
+  MORECORE                  (default: sbrk)
+     The name of the routine to call to obtain more memory from the system.
+  MORECORE_FAILURE          (default: -1)
+     The value returned upon failure of MORECORE.
+  MORECORE_CLEARS           (default 1)
+     true (1) if the routine mapped to MORECORE zeroes out memory (which
+     holds for sbrk).
+  DEFAULT_TRIM_THRESHOLD
+  DEFAULT_TOP_PAD
+  DEFAULT_MMAP_THRESHOLD
+  DEFAULT_MMAP_MAX
+     Default values of tunable parameters (described in detail below)
+     controlling interaction with host system routines (sbrk, mmap, etc).
+     These values may also be changed dynamically via mallopt(). The
+     preset defaults are those that give best performance for typical
+     programs/systems.
+  USE_DL_PREFIX             (default: undefined)
+     Prefix all public routines with the string 'dl'.  Useful to
+     quickly avoid procedure declaration conflicts and linker symbol
+     conflicts with existing memory allocation routines.
+
+
+*/
+
+
+#ifndef __MALLOC_H__
+#define __MALLOC_H__
+
+/* Preliminaries */
+
+#ifndef __STD_C
+#ifdef __STDC__
+#define __STD_C     1
+#else
+#if __cplusplus
+#define __STD_C     1
+#else
+#define __STD_C     0
+#endif /*__cplusplus*/
+#endif /*__STDC__*/
+#endif /*__STD_C*/
+
+#ifndef Void_t
+#if (__STD_C || defined(WIN32))
+#define Void_t      void
+#else
+#define Void_t      char
+#endif
+#endif /*Void_t*/
+
+#if __STD_C
+#include <types.h>	/* for size_t */
+#else
+#include <sys/types.h>
+#endif	/* __STD_C */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define assert(x) ((void)0)
+
+#if 0	/* not for U-Boot */
+#include <stdio.h>	/* needed for malloc_stats */
+#endif
+
+
+/*
+  Compile-time options
+*/
+
+
+/*
+    Debugging:
+
+    Because freed chunks may be overwritten with link fields, this
+    malloc will often die when freed memory is overwritten by user
+    programs.  This can be very effective (albeit in an annoying way)
+    in helping track down dangling pointers.
+
+    If you compile with -DDEBUG, a number of assertion checks are
+    enabled that will catch more memory errors. You probably won't be
+    able to make much sense of the actual assertion errors, but they
+    should help you locate incorrectly overwritten memory.  The
+    checking is fairly extensive, and will slow down execution
+    noticeably. Calling malloc_stats or mallinfo with DEBUG set will
+    attempt to check every non-mmapped allocated and free chunk in the
+    course of computing the summmaries. (By nature, mmapped regions
+    cannot be checked very much automatically.)
+
+    Setting DEBUG may also be helpful if you are trying to modify
+    this code. The assertions in the check routines spell out in more
+    detail the assumptions and invariants underlying the algorithms.
+
+*/
+
+/*
+  INTERNAL_SIZE_T is the word-size used for internal bookkeeping
+  of chunk sizes. On a 64-bit machine, you can reduce malloc
+  overhead by defining INTERNAL_SIZE_T to be a 32 bit `unsigned int'
+  at the expense of not being able to handle requests greater than
+  2^31. This limitation is hardly ever a concern; you are encouraged
+  to set this. However, the default version is the same as size_t.
+*/
+
+#ifndef INTERNAL_SIZE_T
+#define INTERNAL_SIZE_T size_t
+#endif
+
+/*
+  REALLOC_ZERO_BYTES_FREES should be set if a call to
+  realloc with zero bytes should be the same as a call to free.
+  Some people think it should. Otherwise, since this malloc
+  returns a unique pointer for malloc(0), so does realloc(p, 0).
+*/
+
+
+/*   #define REALLOC_ZERO_BYTES_FREES */
+
+
+/*
+  WIN32 causes an emulation of sbrk to be compiled in
+  mmap-based options are not currently supported in WIN32.
+*/
+
+/* #define WIN32 */
+#ifdef WIN32
+#define MORECORE wsbrk
+#define HAVE_MMAP 0
+
+#define LACKS_UNISTD_H
+#define LACKS_SYS_PARAM_H
+
+/*
+  Include 'windows.h' to get the necessary declarations for the
+  Microsoft Visual C++ data structures and routines used in the 'sbrk'
+  emulation.
+
+  Define WIN32_LEAN_AND_MEAN so that only the essential Microsoft
+  Visual C++ header files are included.
+*/
+#define WIN32_LEAN_AND_MEAN
+#include <windows.h>
+#endif
+
+
+/*
+  HAVE_MEMCPY should be defined if you are not otherwise using
+  ANSI STD C, but still have memcpy and memset in your C library
+  and want to use them in calloc and realloc. Otherwise simple
+  macro versions are defined here.
+
+  USE_MEMCPY should be defined as 1 if you actually want to
+  have memset and memcpy called. People report that the macro
+  versions are often enough faster than libc versions on many
+  systems that it is better to use them.
+
+*/
+
+#define HAVE_MEMCPY
+
+#ifndef USE_MEMCPY
+#ifdef HAVE_MEMCPY
+#define USE_MEMCPY 1
+#else
+#define USE_MEMCPY 0
+#endif
+#endif
+
+#if (__STD_C || defined(HAVE_MEMCPY))
+
+#if __STD_C
+void* memset(void*, int, size_t);
+void* memcpy(void*, const void*, size_t);
+#else
+#ifdef WIN32
+/* On Win32 platforms, 'memset()' and 'memcpy()' are already declared in */
+/* 'windows.h' */
+#else
+Void_t* memset();
+Void_t* memcpy();
+#endif
+#endif
+#endif
+
+#if USE_MEMCPY
+
+/* The following macros are only invoked with (2n+1)-multiples of
+   INTERNAL_SIZE_T units, with a positive integer n. This is exploited
+   for fast inline execution when n is small. */
+
+#define MALLOC_ZERO(charp, nbytes)                                            \
+do {                                                                          \
+  INTERNAL_SIZE_T mzsz = (nbytes);                                            \
+  if(mzsz <= 9*sizeof(mzsz)) {                                                \
+    INTERNAL_SIZE_T* mz = (INTERNAL_SIZE_T*) (charp);                         \
+    if(mzsz >= 5*sizeof(mzsz)) {     *mz++ = 0;                               \
+				     *mz++ = 0;                               \
+      if(mzsz >= 7*sizeof(mzsz)) {   *mz++ = 0;                               \
+				     *mz++ = 0;                               \
+	if(mzsz >= 9*sizeof(mzsz)) { *mz++ = 0;                               \
+				     *mz++ = 0; }}}                           \
+				     *mz++ = 0;                               \
+				     *mz++ = 0;                               \
+				     *mz   = 0;                               \
+  } else memset((charp), 0, mzsz);                                            \
+} while(0)
+
+#define MALLOC_COPY(dest,src,nbytes)                                          \
+do {                                                                          \
+  INTERNAL_SIZE_T mcsz = (nbytes);                                            \
+  if(mcsz <= 9*sizeof(mcsz)) {                                                \
+    INTERNAL_SIZE_T* mcsrc = (INTERNAL_SIZE_T*) (src);                        \
+    INTERNAL_SIZE_T* mcdst = (INTERNAL_SIZE_T*) (dest);                       \
+    if(mcsz >= 5*sizeof(mcsz)) {     *mcdst++ = *mcsrc++;                     \
+				     *mcdst++ = *mcsrc++;                     \
+      if(mcsz >= 7*sizeof(mcsz)) {   *mcdst++ = *mcsrc++;                     \
+				     *mcdst++ = *mcsrc++;                     \
+	if(mcsz >= 9*sizeof(mcsz)) { *mcdst++ = *mcsrc++;                     \
+				     *mcdst++ = *mcsrc++; }}}                 \
+				     *mcdst++ = *mcsrc++;                     \
+				     *mcdst++ = *mcsrc++;                     \
+				     *mcdst   = *mcsrc  ;                     \
+  } else memcpy(dest, src, mcsz);                                             \
+} while(0)
+
+#else /* !USE_MEMCPY */
+
+/* Use Duff's device for good zeroing/copying performance. */
+
+#define MALLOC_ZERO(charp, nbytes)                                            \
+do {                                                                          \
+  INTERNAL_SIZE_T* mzp = (INTERNAL_SIZE_T*)(charp);                           \
+  long mctmp = (nbytes)/sizeof(INTERNAL_SIZE_T), mcn;                         \
+  if (mctmp < 8) mcn = 0; else { mcn = (mctmp-1)/8; mctmp %= 8; }             \
+  switch (mctmp) {                                                            \
+    case 0: for(;;) { *mzp++ = 0;                                             \
+    case 7:           *mzp++ = 0;                                             \
+    case 6:           *mzp++ = 0;                                             \
+    case 5:           *mzp++ = 0;                                             \
+    case 4:           *mzp++ = 0;                                             \
+    case 3:           *mzp++ = 0;                                             \
+    case 2:           *mzp++ = 0;                                             \
+    case 1:           *mzp++ = 0; if(mcn <= 0) break; mcn--; }                \
+  }                                                                           \
+} while(0)
+
+#define MALLOC_COPY(dest,src,nbytes)                                          \
+do {                                                                          \
+  INTERNAL_SIZE_T* mcsrc = (INTERNAL_SIZE_T*) src;                            \
+  INTERNAL_SIZE_T* mcdst = (INTERNAL_SIZE_T*) dest;                           \
+  long mctmp = (nbytes)/sizeof(INTERNAL_SIZE_T), mcn;                         \
+  if (mctmp < 8) mcn = 0; else { mcn = (mctmp-1)/8; mctmp %= 8; }             \
+  switch (mctmp) {                                                            \
+    case 0: for(;;) { *mcdst++ = *mcsrc++;                                    \
+    case 7:           *mcdst++ = *mcsrc++;                                    \
+    case 6:           *mcdst++ = *mcsrc++;                                    \
+    case 5:           *mcdst++ = *mcsrc++;                                    \
+    case 4:           *mcdst++ = *mcsrc++;                                    \
+    case 3:           *mcdst++ = *mcsrc++;                                    \
+    case 2:           *mcdst++ = *mcsrc++;                                    \
+    case 1:           *mcdst++ = *mcsrc++; if(mcn <= 0) break; mcn--; }       \
+  }                                                                           \
+} while(0)
+
+#endif
+
+
+/*
+  Define HAVE_MMAP to optionally make malloc() use mmap() to
+  allocate very large blocks.  These will be returned to the
+  operating system immediately after a free().
+*/
+
+/***
+#ifndef HAVE_MMAP
+#define HAVE_MMAP 1
+#endif
+***/
+#undef	HAVE_MMAP	/* Not available for U-Boot */
+
+/*
+  Define HAVE_MREMAP to make realloc() use mremap() to re-allocate
+  large blocks.  This is currently only possible on Linux with
+  kernel versions newer than 1.3.77.
+*/
+
+/***
+#ifndef HAVE_MREMAP
+#ifdef INTERNAL_LINUX_C_LIB
+#define HAVE_MREMAP 1
+#else
+#define HAVE_MREMAP 0
+#endif
+#endif
+***/
+#undef	HAVE_MREMAP	/* Not available for U-Boot */
+
+#ifdef HAVE_MMAP
+
+#include <unistd.h>
+#include <fcntl.h>
+#include <sys/mman.h>
+
+#if !defined(MAP_ANONYMOUS) && defined(MAP_ANON)
+#define MAP_ANONYMOUS MAP_ANON
+#endif
+
+#endif /* HAVE_MMAP */
+
+/*
+  Access to system page size. To the extent possible, this malloc
+  manages memory from the system in page-size units.
+
+  The following mechanics for getpagesize were adapted from
+  bsd/gnu getpagesize.h
+*/
+
+#define	LACKS_UNISTD_H	/* Shortcut for U-Boot */
+#define	malloc_getpagesize	4096
+
+#ifndef LACKS_UNISTD_H
+#  include <unistd.h>
+#endif
+
+#ifndef malloc_getpagesize
+#  ifdef _SC_PAGESIZE         /* some SVR4 systems omit an underscore */
+#    ifndef _SC_PAGE_SIZE
+#      define _SC_PAGE_SIZE _SC_PAGESIZE
+#    endif
+#  endif
+#  ifdef _SC_PAGE_SIZE
+#    define malloc_getpagesize sysconf(_SC_PAGE_SIZE)
+#  else
+#    if defined(BSD) || defined(DGUX) || defined(HAVE_GETPAGESIZE)
+       extern size_t getpagesize();
+#      define malloc_getpagesize getpagesize()
+#    else
+#      ifdef WIN32
+#        define malloc_getpagesize (4096) /* TBD: Use 'GetSystemInfo' instead */
+#      else
+#        ifndef LACKS_SYS_PARAM_H
+#          include <sys/param.h>
+#        endif
+#        ifdef EXEC_PAGESIZE
+#          define malloc_getpagesize EXEC_PAGESIZE
+#        else
+#          ifdef NBPG
+#            ifndef CLSIZE
+#              define malloc_getpagesize NBPG
+#            else
+#              define malloc_getpagesize (NBPG * CLSIZE)
+#            endif
+#          else
+#            ifdef NBPC
+#              define malloc_getpagesize NBPC
+#            else
+#              ifdef PAGESIZE
+#                define malloc_getpagesize PAGESIZE
+#              else
+#                define malloc_getpagesize (4096) /* just guess */
+#              endif
+#            endif
+#          endif
+#        endif
+#      endif
+#    endif
+#  endif
+#endif
+
+
+/*
+
+  This version of malloc supports the standard SVID/XPG mallinfo
+  routine that returns a struct containing the same kind of
+  information you can get from malloc_stats. It should work on
+  any SVID/XPG compliant system that has a /usr/include/malloc.h
+  defining struct mallinfo. (If you'd like to install such a thing
+  yourself, cut out the preliminary declarations as described above
+  and below and save them in a malloc.h file. But there's no
+  compelling reason to bother to do this.)
+
+  The main declaration needed is the mallinfo struct that is returned
+  (by-copy) by mallinfo().  The SVID/XPG malloinfo struct contains a
+  bunch of fields, most of which are not even meaningful in this
+  version of malloc. Some of these fields are are instead filled by
+  mallinfo() with other numbers that might possibly be of interest.
+
+  HAVE_USR_INCLUDE_MALLOC_H should be set if you have a
+  /usr/include/malloc.h file that includes a declaration of struct
+  mallinfo.  If so, it is included; else an SVID2/XPG2 compliant
+  version is declared below.  These must be precisely the same for
+  mallinfo() to work.
+
+*/
+
+/* #define HAVE_USR_INCLUDE_MALLOC_H */
+
+#ifdef HAVE_USR_INCLUDE_MALLOC_H
+#include "/usr/include/malloc.h"
+#else
+
+/* SVID2/XPG mallinfo structure */
+
+struct mallinfo {
+  int arena;    /* total space allocated from system */
+  int ordblks;  /* number of non-inuse chunks */
+  int smblks;   /* unused -- always zero */
+  int hblks;    /* number of mmapped regions */
+  int hblkhd;   /* total space in mmapped regions */
+  int usmblks;  /* unused -- always zero */
+  int fsmblks;  /* unused -- always zero */
+  int uordblks; /* total allocated space */
+  int fordblks; /* total non-inuse space */
+  int keepcost; /* top-most, releasable (via malloc_trim) space */
+};
+
+/* SVID2/XPG mallopt options */
+
+#define M_MXFAST  1    /* UNUSED in this malloc */
+#define M_NLBLKS  2    /* UNUSED in this malloc */
+#define M_GRAIN   3    /* UNUSED in this malloc */
+#define M_KEEP    4    /* UNUSED in this malloc */
+
+#endif
+
+/* mallopt options that actually do something */
+
+#define M_TRIM_THRESHOLD    -1
+#define M_TOP_PAD           -2
+#define M_MMAP_THRESHOLD    -3
+#define M_MMAP_MAX          -4
+
+
+#ifndef DEFAULT_TRIM_THRESHOLD
+#define DEFAULT_TRIM_THRESHOLD (128 * 1024)
+#endif
+
+/*
+    M_TRIM_THRESHOLD is the maximum amount of unused top-most memory
+      to keep before releasing via malloc_trim in free().
+
+      Automatic trimming is mainly useful in long-lived programs.
+      Because trimming via sbrk can be slow on some systems, and can
+      sometimes be wasteful (in cases where programs immediately
+      afterward allocate more large chunks) the value should be high
+      enough so that your overall system performance would improve by
+      releasing.
+
+      The trim threshold and the mmap control parameters (see below)
+      can be traded off with one another. Trimming and mmapping are
+      two different ways of releasing unused memory back to the
+      system. Between these two, it is often possible to keep
+      system-level demands of a long-lived program down to a bare
+      minimum. For example, in one test suite of sessions measuring
+      the XF86 X server on Linux, using a trim threshold of 128K and a
+      mmap threshold of 192K led to near-minimal long term resource
+      consumption.
+
+      If you are using this malloc in a long-lived program, it should
+      pay to experiment with these values.  As a rough guide, you
+      might set to a value close to the average size of a process
+      (program) running on your system.  Releasing this much memory
+      would allow such a process to run in memory.  Generally, it's
+      worth it to tune for trimming rather tham memory mapping when a
+      program undergoes phases where several large chunks are
+      allocated and released in ways that can reuse each other's
+      storage, perhaps mixed with phases where there are no such
+      chunks at all.  And in well-behaved long-lived programs,
+      controlling release of large blocks via trimming versus mapping
+      is usually faster.
+
+      However, in most programs, these parameters serve mainly as
+      protection against the system-level effects of carrying around
+      massive amounts of unneeded memory. Since frequent calls to
+      sbrk, mmap, and munmap otherwise degrade performance, the default
+      parameters are set to relatively high values that serve only as
+      safeguards.
+
+      The default trim value is high enough to cause trimming only in
+      fairly extreme (by current memory consumption standards) cases.
+      It must be greater than page size to have any useful effect.  To
+      disable trimming completely, you can set to (unsigned long)(-1);
+
+
+*/
+
+
+#ifndef DEFAULT_TOP_PAD
+#define DEFAULT_TOP_PAD        (0)
+#endif
+
+/*
+    M_TOP_PAD is the amount of extra `padding' space to allocate or
+      retain whenever sbrk is called. It is used in two ways internally:
+
+      * When sbrk is called to extend the top of the arena to satisfy
+	a new malloc request, this much padding is added to the sbrk
+	request.
+
+      * When malloc_trim is called automatically from free(),
+	it is used as the `pad' argument.
+
+      In both cases, the actual amount of padding is rounded
+      so that the end of the arena is always a system page boundary.
+
+      The main reason for using padding is to avoid calling sbrk so
+      often. Having even a small pad greatly reduces the likelihood
+      that nearly every malloc request during program start-up (or
+      after trimming) will invoke sbrk, which needlessly wastes
+      time.
+
+      Automatic rounding-up to page-size units is normally sufficient
+      to avoid measurable overhead, so the default is 0.  However, in
+      systems where sbrk is relatively slow, it can pay to increase
+      this value, at the expense of carrying around more memory than
+      the program needs.
+
+*/
+
+
+#ifndef DEFAULT_MMAP_THRESHOLD
+#define DEFAULT_MMAP_THRESHOLD (128 * 1024)
+#endif
+
+/*
+
+    M_MMAP_THRESHOLD is the request size threshold for using mmap()
+      to service a request. Requests of at least this size that cannot
+      be allocated using already-existing space will be serviced via mmap.
+      (If enough normal freed space already exists it is used instead.)
+
+      Using mmap segregates relatively large chunks of memory so that
+      they can be individually obtained and released from the host
+      system. A request serviced through mmap is never reused by any
+      other request (at least not directly; the system may just so
+      happen to remap successive requests to the same locations).
+
+      Segregating space in this way has the benefit that mmapped space
+      can ALWAYS be individually released back to the system, which
+      helps keep the system level memory demands of a long-lived
+      program low. Mapped memory can never become `locked' between
+      other chunks, as can happen with normally allocated chunks, which
+      menas that even trimming via malloc_trim would not release them.
+
+      However, it has the disadvantages that:
+
+	 1. The space cannot be reclaimed, consolidated, and then
+	    used to service later requests, as happens with normal chunks.
+	 2. It can lead to more wastage because of mmap page alignment
+	    requirements
+	 3. It causes malloc performance to be more dependent on host
+	    system memory management support routines which may vary in
+	    implementation quality and may impose arbitrary
+	    limitations. Generally, servicing a request via normal
+	    malloc steps is faster than going through a system's mmap.
+
+      All together, these considerations should lead you to use mmap
+      only for relatively large requests.
+
+
+*/
+
+
+#ifndef DEFAULT_MMAP_MAX
+#ifdef HAVE_MMAP
+#define DEFAULT_MMAP_MAX       (64)
+#else
+#define DEFAULT_MMAP_MAX       (0)
+#endif
+#endif
+
+/*
+    M_MMAP_MAX is the maximum number of requests to simultaneously
+      service using mmap. This parameter exists because:
+
+	 1. Some systems have a limited number of internal tables for
+	    use by mmap.
+	 2. In most systems, overreliance on mmap can degrade overall
+	    performance.
+	 3. If a program allocates many large regions, it is probably
+	    better off using normal sbrk-based allocation routines that
+	    can reclaim and reallocate normal heap memory. Using a
+	    small value allows transition into this mode after the
+	    first few allocations.
+
+      Setting to 0 disables all use of mmap.  If HAVE_MMAP is not set,
+      the default value is 0, and attempts to set it to non-zero values
+      in mallopt will fail.
+*/
+
+
+/*
+    USE_DL_PREFIX will prefix all public routines with the string 'dl'.
+      Useful to quickly avoid procedure declaration conflicts and linker
+      symbol conflicts with existing memory allocation routines.
+
+*/
+
+/* #define USE_DL_PREFIX */
+
+
+/*
+
+  Special defines for linux libc
+
+  Except when compiled using these special defines for Linux libc
+  using weak aliases, this malloc is NOT designed to work in
+  multithreaded applications.  No semaphores or other concurrency
+  control are provided to ensure that multiple malloc or free calls
+  don't run at the same time, which could be disasterous. A single
+  semaphore could be used across malloc, realloc, and free (which is
+  essentially the effect of the linux weak alias approach). It would
+  be hard to obtain finer granularity.
+
+*/
+
+
+#ifdef INTERNAL_LINUX_C_LIB
+
+#if __STD_C
+
+Void_t * __default_morecore_init (ptrdiff_t);
+Void_t *(*__morecore)(ptrdiff_t) = __default_morecore_init;
+
+#else
+
+Void_t * __default_morecore_init ();
+Void_t *(*__morecore)() = __default_morecore_init;
+
+#endif
+
+#define MORECORE (*__morecore)
+#define MORECORE_FAILURE 0
+#define MORECORE_CLEARS 1
+
+#else /* INTERNAL_LINUX_C_LIB */
+
+#if __STD_C
+extern Void_t*     sbrk(ptrdiff_t);
+#else
+extern Void_t*     sbrk();
+#endif
+
+#ifndef MORECORE
+#define MORECORE sbrk
+#endif
+
+#ifndef MORECORE_FAILURE
+#define MORECORE_FAILURE -1
+#endif
+
+#ifndef MORECORE_CLEARS
+#define MORECORE_CLEARS 1
+#endif
+
+#endif /* INTERNAL_LINUX_C_LIB */
+
+#if defined(INTERNAL_LINUX_C_LIB) && defined(__ELF__)
+
+#define cALLOc		__libc_calloc
+#define fREe		__libc_free
+#define mALLOc		__libc_malloc
+#define mEMALIGn	__libc_memalign
+#define rEALLOc		__libc_realloc
+#define vALLOc		__libc_valloc
+#define pvALLOc		__libc_pvalloc
+#define mALLINFo	__libc_mallinfo
+#define mALLOPt		__libc_mallopt
+
+#pragma weak calloc = __libc_calloc
+#pragma weak free = __libc_free
+#pragma weak cfree = __libc_free
+#pragma weak malloc = __libc_malloc
+#pragma weak memalign = __libc_memalign
+#pragma weak realloc = __libc_realloc
+#pragma weak valloc = __libc_valloc
+#pragma weak pvalloc = __libc_pvalloc
+#pragma weak mallinfo = __libc_mallinfo
+#pragma weak mallopt = __libc_mallopt
+
+#else
+
+#ifdef USE_DL_PREFIX
+#define cALLOc		dlcalloc
+#define fREe		dlfree
+#define mALLOc		dlmalloc
+#define mEMALIGn	dlmemalign
+#define rEALLOc		dlrealloc
+#define vALLOc		dlvalloc
+#define pvALLOc		dlpvalloc
+#define mALLINFo	dlmallinfo
+#define mALLOPt		dlmallopt
+#else /* USE_DL_PREFIX */
+#define cALLOc		calloc
+#define fREe		free
+#define mALLOc		malloc
+#define mEMALIGn	memalign
+#define rEALLOc		realloc
+#define vALLOc		valloc
+#define pvALLOc		pvalloc
+#define mALLINFo	mallinfo
+#define mALLOPt		mallopt
+#endif /* USE_DL_PREFIX */
+
+#endif
+
+/* Public routines */
+
+#if __STD_C
+
+Void_t* mALLOc(size_t);
+void    fREe(Void_t*);
+Void_t* rEALLOc(Void_t*, size_t);
+Void_t* mEMALIGn(size_t, size_t);
+Void_t* vALLOc(size_t);
+Void_t* pvALLOc(size_t);
+Void_t* cALLOc(size_t, size_t);
+void    cfree(Void_t*);
+int     malloc_trim(size_t);
+size_t  malloc_usable_size(Void_t*);
+void    malloc_stats(void);
+int     mALLOPt(int, int);
+struct mallinfo mALLINFo(void);
+#else
+Void_t* mALLOc();
+void    fREe();
+Void_t* rEALLOc();
+Void_t* mEMALIGn();
+Void_t* vALLOc();
+Void_t* pvALLOc();
+Void_t* cALLOc();
+void    cfree();
+int     malloc_trim();
+size_t  malloc_usable_size();
+void    malloc_stats();
+int     mALLOPt();
+struct mallinfo mALLINFo();
+#endif
+
+/*
+ * Begin and End of memory area for malloc(), and current "brk"
+ */
+extern ulong mem_malloc_start;
+extern ulong mem_malloc_end;
+extern ulong mem_malloc_brk;
+
+void mem_malloc_init(ulong start, ulong size);
+
+#ifdef __cplusplus
+};  /* end of extern "C" */
+#endif
+
+#endif /* __MALLOC_H__ */
diff --git a/linux-bsp/asm-study/yaffs2/common/printf.c b/linux-bsp/asm-study/yaffs2/common/printf.c
new file mode 100644
index 0000000..708420c
--- /dev/null
+++ b/linux-bsp/asm-study/yaffs2/common/printf.c
@@ -0,0 +1,374 @@
+/*
+ *  linux/lib/vsprintf.c
+ *
+ *  Copyright (C) 1991, 1992  Linus Torvalds
+ */
+
+/* vsprintf.c -- Lars Wirzenius & Linus Torvalds. */
+/*
+ * Wirzenius wrote this portably, Torvalds fucked it up :-)
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include "s3c_board.h"
+
+#define CFG_PBSIZE                  1024 /*  Print Buffer Size */
+
+#define is_digit(c)	((c) >= '0' && (c) <= '9')
+
+static int skip_atoi(const char **s)
+{
+    int i = 0;
+
+    while (is_digit(**s))
+        i = i * 10 + *((*s)++) - '0';
+    return i;
+}
+
+#define ZEROPAD	1               /* pad with zero */
+#define SIGN	2               /* unsigned/signed long */
+#define PLUS	4               /* show plus */
+#define SPACE	8               /* space if plus */
+#define LEFT	16              /* left justified */
+#define SPECIAL	32              /* 0x */
+#define LARGE	64              /* use 'ABCDEF' instead of 'abcdef' */
+
+#ifdef CFG_64BIT_VSPRINTF
+#define do_div(n,base) ({ \
+	unsigned int __res; \
+	__res = ((unsigned long long) n) % base; \
+	n = ((unsigned long long) n) / base; \
+	__res; \
+})
+#else
+#define do_div(n,base) ({ \
+	int __res; \
+	__res = ((unsigned long) n) % base; \
+	n = ((unsigned long) n) / base; \
+	__res; \
+})
+#endif
+
+#ifdef CFG_64BIT_VSPRINTF
+static char *number(char *str, long long num, unsigned int base, int size, int precision, int type)
+#else
+static char *number(char *str, long num, unsigned int base, int size, int precision, int type)
+#endif
+{
+    char c, sign, tmp[66];
+    const char *digits = "0123456789abcdefghijklmnopqrstuvwxyz";
+    int i;
+
+    if (type & LARGE)
+        digits = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
+    if (type & LEFT)
+        type &= ~ZEROPAD;
+    if (base < 2 || base > 36)
+        return 0;
+    c = (type & ZEROPAD) ? '0' : ' ';
+    sign = 0;
+    if (type & SIGN)
+    {
+        if (num < 0)
+        {
+            sign = '-';
+            num = -num;
+            size--;
+        }
+        else if (type & PLUS)
+        {
+            sign = '+';
+            size--;
+        }
+        else if (type & SPACE)
+        {
+            sign = ' ';
+            size--;
+        }
+    }
+    if (type & SPECIAL)
+    {
+        if (base == 16)
+            size -= 2;
+        else if (base == 8)
+            size--;
+    }
+    i = 0;
+    if (num == 0)
+        tmp[i++] = '0';
+    else
+        while (num != 0)
+            tmp[i++] = digits[do_div(num, base)];
+    if (i > precision)
+        precision = i;
+    size -= precision;
+    if (!(type & (ZEROPAD + LEFT)))
+        while (size-- > 0)
+            *str++ = ' ';
+    if (sign)
+        *str++ = sign;
+    if (type & SPECIAL)
+    {
+        if (base == 8)
+            *str++ = '0';
+        else if (base == 16)
+        {
+            *str++ = '0';
+            *str++ = digits[33];
+        }
+    }
+    if (!(type & LEFT))
+        while (size-- > 0)
+            *str++ = c;
+    while (i < precision--)
+        *str++ = '0';
+    while (i-- > 0)
+        *str++ = tmp[i];
+    while (size-- > 0)
+        *str++ = ' ';
+    return str;
+}
+
+/* Forward decl. needed for IP address printing stuff... */
+int sprintf(char *buf, const char *fmt, ...);
+
+int vsprintf(char *buf, const char *fmt, va_list args)
+{
+    int len;
+#ifdef CFG_64BIT_VSPRINTF
+    unsigned long long num;
+#else
+    unsigned long num;
+#endif
+    int i, base;
+    char *str;
+    const char *s;
+
+    int flags;                  /* flags to number() */
+
+    int field_width;            /* width of output field */
+    int precision;              /* min. # of digits for integers; max
+                                 * number of chars for from string */
+    int qualifier;              /* 'h', 'l', or 'q' for integer fields */
+
+    for (str = buf; *fmt; ++fmt)
+    {
+        if (*fmt != '%')
+        {
+            *str++ = *fmt;
+            continue;
+        }
+
+        /* process flags */
+        flags = 0;
+      repeat:
+        ++fmt;                  /* this also skips first '%' */
+        switch (*fmt)
+        {
+          case '-':
+              flags |= LEFT;
+              goto repeat;
+          case '+':
+              flags |= PLUS;
+              goto repeat;
+          case ' ':
+              flags |= SPACE;
+              goto repeat;
+          case '#':
+              flags |= SPECIAL;
+              goto repeat;
+          case '0':
+              flags |= ZEROPAD;
+              goto repeat;
+        }
+
+        /* get field width */
+        field_width = -1;
+        if (is_digit(*fmt))
+            field_width = skip_atoi(&fmt);
+        else if (*fmt == '*')
+        {
+            ++fmt;
+            /* it's the next argument */
+            field_width = va_arg(args, int);
+            if (field_width < 0)
+            {
+                field_width = -field_width;
+                flags |= LEFT;
+            }
+        }
+
+        /* get the precision */
+        precision = -1;
+        if (*fmt == '.')
+        {
+            ++fmt;
+            if (is_digit(*fmt))
+                precision = skip_atoi(&fmt);
+            else if (*fmt == '*')
+            {
+                ++fmt;
+                /* it's the next argument */
+                precision = va_arg(args, int);
+            }
+            if (precision < 0)
+                precision = 0;
+        }
+
+        /* get the conversion qualifier */
+        qualifier = -1;
+        if (*fmt == 'h' || *fmt == 'l' || *fmt == 'L' ||
+            *fmt == 'Z' || *fmt == 'z' || *fmt == 't' || *fmt == 'q')
+        {
+            qualifier = *fmt;
+            if (qualifier == 'l' && *(fmt + 1) == 'l')
+            {
+                qualifier = 'q';
+                ++fmt;
+            }
+            ++fmt;
+        }
+
+        /* default base */
+        base = 10;
+
+        switch (*fmt)
+        {
+          case 'c':
+              if (!(flags & LEFT))
+                  while (--field_width > 0)
+                      *str++ = ' ';
+              *str++ = (unsigned char)va_arg(args, int);
+              while (--field_width > 0)
+                  *str++ = ' ';
+              continue;
+
+          case 's':
+              s = va_arg(args, char *);
+              if (!s)
+                  s = "<NULL>";
+
+              len = strnlen(s, precision);
+
+              if (!(flags & LEFT))
+                  while (len < field_width--)
+                      *str++ = ' ';
+              for (i = 0; i < len; ++i)
+                  *str++ = *s++;
+              while (len < field_width--)
+                  *str++ = ' ';
+              continue;
+
+          case 'p':
+              if (field_width == -1)
+              {
+                  field_width = 2 * sizeof(void *);
+                  flags |= ZEROPAD;
+              }
+              str = number(str,
+                           (unsigned long)va_arg(args, void *), 16, field_width, precision, flags);
+              continue;
+
+          case 'n':
+              if (qualifier == 'l')
+              {
+                  long *ip = va_arg(args, long *);
+                  *ip = (str - buf);
+              }
+              else
+              {
+                  int *ip = va_arg(args, int *);
+                  *ip = (str - buf);
+              }
+              continue;
+
+          case '%':
+              *str++ = '%';
+              continue;
+
+              /* integer number formats - set up the flags and "break" */
+          case 'o':
+              base = 8;
+              break;
+
+          case 'X':
+              flags |= LARGE;
+          case 'x':
+              base = 16;
+              break;
+
+          case 'd':
+          case 'i':
+              flags |= SIGN;
+          case 'u':
+              break;
+
+          default:
+              *str++ = '%';
+              if (*fmt)
+                  *str++ = *fmt;
+              else
+                  --fmt;
+              continue;
+        }
+#ifdef CFG_64BIT_VSPRINTF
+        if (qualifier == 'q')   /* "quad" for 64 bit variables */
+            num = va_arg(args, unsigned long long);
+        else
+#endif
+        if (qualifier == 'l')
+        {
+            num = va_arg(args, unsigned long);
+        }
+        else if (qualifier == 'Z' || qualifier == 'z')
+        {
+            num = va_arg(args, size_t);
+        }
+        else if (qualifier == 't')
+        {
+            num = va_arg(args, ptrdiff_t);
+        }
+        else if (qualifier == 'h')
+        {
+            num = (unsigned short)va_arg(args, int);
+            if (flags & SIGN)
+                num = (short)num;
+        }
+        else if (flags & SIGN)
+            num = va_arg(args, int);
+        else
+            num = va_arg(args, unsigned int);
+        str = number(str, num, base, field_width, precision, flags);
+    }
+    *str = '\0';
+    return str - buf;
+}
+
+void printf(const char *fmt, ...)
+{
+    va_list args;
+    uint i;
+    char printbuffer[CFG_PBSIZE];
+
+    va_start(args, fmt);
+
+    /* For this to work, printbuffer must be larger than
+     * anything we ever want to print.
+     */
+    i = vsprintf(printbuffer, fmt, args);
+    va_end(args);
+
+    console_serial_puts(printbuffer);
+}
+
+int sprintf(char *buf, const char *fmt, ...)
+{
+    va_list args;
+    int i;
+
+    va_start(args, fmt);
+    i = vsprintf(buf, fmt, args);
+    va_end(args);
+    return i;
+}
diff --git a/linux-bsp/asm-study/yaffs2/common/stdio.h b/linux-bsp/asm-study/yaffs2/common/stdio.h
new file mode 100644
index 0000000..64171b4
--- /dev/null
+++ b/linux-bsp/asm-study/yaffs2/common/stdio.h
@@ -0,0 +1,32 @@
+/********************************************************************************************
+ *        File:  common.h
+ *     Version:  1.0.0
+ *   Copyright:  2011 (c) Guo Wenxue <guowenxue@gmail.com>
+ * Description:  A busy head file
+ *   ChangeLog:  1, Release initial version on "Tue Jul 12 16:43:18 CST 2011"
+ *
+ *******************************************************************************************/
+
+#ifndef __COMMON_H
+#define __COMMON_H
+
+#include <stdarg.h>
+#include <types.h>
+
+#ifdef DEBUG
+#define dbg_print(format,args...) printf(format, ##args)
+#else
+#define dbg_print(format,args...) do{} while(0);
+#endif
+
+void serial_init(void);
+void serial_send_byte(char c);
+int serial_is_recv_enable(void);
+int serial_recv_byte(void);
+void serial_puts(const char *s);
+
+/*Define in printf.c*/
+void printf(const char *fmt, ...);
+int sprintf(char *buf, const char *fmt, ...);
+
+#endif
diff --git a/linux-bsp/asm-study/yaffs2/common/string.c b/linux-bsp/asm-study/yaffs2/common/string.c
new file mode 100644
index 0000000..46ea471
--- /dev/null
+++ b/linux-bsp/asm-study/yaffs2/common/string.c
@@ -0,0 +1,603 @@
+/*
+ *  linux/lib/string.c
+ *
+ *  Copyright (C) 1991, 1992  Linus Torvalds
+ */
+
+/*
+ * stupid library routines.. The optimized versions should generally be found
+ * as inline code in <asm-xx/string.h>
+ *
+ * These are buggy as well..
+ *
+ * * Fri Jun 25 1999, Ingo Oeser <ioe@informatik.tu-chemnitz.de>
+ * -  Added strsep() which will replace strtok() soon (because strsep() is
+ *    reentrant and should be faster). Use only strsep() in new code, please.
+ */
+
+#include <types.h>
+#include <malloc.h>
+
+
+#if 0 /* not used - was: #ifndef __HAVE_ARCH_STRNICMP */
+/**
+ * strnicmp - Case insensitive, length-limited string comparison
+ * @s1: One string
+ * @s2: The other string
+ * @len: the maximum number of characters to compare
+ */
+int strnicmp(const char *s1, const char *s2, size_t len)
+{
+	/* Yes, Virginia, it had better be unsigned */
+	unsigned char c1, c2;
+
+	c1 = 0;	c2 = 0;
+	if (len) {
+		do {
+			c1 = *s1; c2 = *s2;
+			s1++; s2++;
+			if (!c1)
+				break;
+			if (!c2)
+				break;
+			if (c1 == c2)
+				continue;
+			c1 = tolower(c1);
+			c2 = tolower(c2);
+			if (c1 != c2)
+				break;
+		} while (--len);
+	}
+	return (int)c1 - (int)c2;
+}
+#endif
+
+char * ___strtok;
+
+#ifndef __HAVE_ARCH_STRCPY
+/**
+ * strcpy - Copy a %NUL terminated string
+ * @dest: Where to copy the string to
+ * @src: Where to copy the string from
+ */
+char * strcpy(char * dest,const char *src)
+{
+	char *tmp = dest;
+
+	while ((*dest++ = *src++) != '\0')
+		/* nothing */;
+	return tmp;
+}
+#endif
+
+#ifndef __HAVE_ARCH_STRNCPY
+/**
+ * strncpy - Copy a length-limited, %NUL-terminated string
+ * @dest: Where to copy the string to
+ * @src: Where to copy the string from
+ * @count: The maximum number of bytes to copy
+ *
+ * Note that unlike userspace strncpy, this does not %NUL-pad the buffer.
+ * However, the result is not %NUL-terminated if the source exceeds
+ * @count bytes.
+ */
+char * strncpy(char * dest,const char *src,size_t count)
+{
+	char *tmp = dest;
+
+	while (count-- && (*dest++ = *src++) != '\0')
+		/* nothing */;
+
+	return tmp;
+}
+#endif
+
+#ifndef __HAVE_ARCH_STRCAT
+/**
+ * strcat - Append one %NUL-terminated string to another
+ * @dest: The string to be appended to
+ * @src: The string to append to it
+ */
+char * strcat(char * dest, const char * src)
+{
+	char *tmp = dest;
+
+	while (*dest)
+		dest++;
+	while ((*dest++ = *src++) != '\0')
+		;
+
+	return tmp;
+}
+#endif
+
+#ifndef __HAVE_ARCH_STRNCAT
+/**
+ * strncat - Append a length-limited, %NUL-terminated string to another
+ * @dest: The string to be appended to
+ * @src: The string to append to it
+ * @count: The maximum numbers of bytes to copy
+ *
+ * Note that in contrast to strncpy, strncat ensures the result is
+ * terminated.
+ */
+char * strncat(char *dest, const char *src, size_t count)
+{
+	char *tmp = dest;
+
+	if (count) {
+		while (*dest)
+			dest++;
+		while ((*dest++ = *src++)) {
+			if (--count == 0) {
+				*dest = '\0';
+				break;
+			}
+		}
+	}
+
+	return tmp;
+}
+#endif
+
+#ifndef __HAVE_ARCH_STRCMP
+/**
+ * strcmp - Compare two strings
+ * @cs: One string
+ * @ct: Another string
+ */
+int strcmp(const char * cs,const char * ct)
+{
+	register signed char __res;
+
+	while (1) {
+		if ((__res = *cs - *ct++) != 0 || !*cs++)
+			break;
+	}
+
+	return __res;
+}
+#endif
+
+#ifndef __HAVE_ARCH_STRNCMP
+/**
+ * strncmp - Compare two length-limited strings
+ * @cs: One string
+ * @ct: Another string
+ * @count: The maximum number of bytes to compare
+ */
+int strncmp(const char * cs,const char * ct,size_t count)
+{
+	register signed char __res = 0;
+
+	while (count) {
+		if ((__res = *cs - *ct++) != 0 || !*cs++)
+			break;
+		count--;
+	}
+
+	return __res;
+}
+#endif
+
+#ifndef __HAVE_ARCH_STRCHR
+/**
+ * strchr - Find the first occurrence of a character in a string
+ * @s: The string to be searched
+ * @c: The character to search for
+ */
+char * strchr(const char * s, int c)
+{
+	for(; *s != (char) c; ++s)
+		if (*s == '\0')
+			return NULL;
+	return (char *) s;
+}
+#endif
+
+#ifndef __HAVE_ARCH_STRLEN
+/**
+ * strlen - Find the length of a string
+ * @s: The string to be sized
+ */
+size_t strlen(const char * s)
+{
+	const char *sc;
+
+	for (sc = s; *sc != '\0'; ++sc)
+		/* nothing */;
+	return sc - s;
+}
+#endif
+
+#ifndef __HAVE_ARCH_STRRCHR
+/**
+ * strrchr - Find the last occurrence of a character in a string
+ * @s: The string to be searched
+ * @c: The character to search for
+ */
+char * strrchr(const char * s, int c)
+{
+       const char *p = s + strlen(s);
+       do {
+	   if (*p == (char)c)
+	       return (char *)p;
+       } while (--p >= s);
+       return NULL;
+}
+#endif
+
+#ifndef __HAVE_ARCH_STRNLEN
+/**
+ * strnlen - Find the length of a length-limited string
+ * @s: The string to be sized
+ * @count: The maximum number of bytes to search
+ */
+size_t strnlen(const char * s, size_t count)
+{
+	const char *sc;
+
+	for (sc = s; count-- && *sc != '\0'; ++sc)
+		/* nothing */;
+	return sc - s;
+}
+#endif
+
+#ifndef __HAVE_ARCH_STRDUP
+char * strdup(const char *s)
+{   
+    char *new; 
+    
+    if ((s == NULL) || ((new = malloc (strlen(s) + 1)) == NULL) ) 
+    { 
+        return NULL;
+    } 
+    
+    strcpy (new, s);
+    return new;
+}   
+#endif
+
+#ifndef __HAVE_ARCH_STRSPN
+/**
+ * strspn - Calculate the length of the initial substring of @s which only
+ *	contain letters in @accept
+ * @s: The string to be searched
+ * @accept: The string to search for
+ */
+size_t strspn(const char *s, const char *accept)
+{
+	const char *p;
+	const char *a;
+	size_t count = 0;
+
+	for (p = s; *p != '\0'; ++p) {
+		for (a = accept; *a != '\0'; ++a) {
+			if (*p == *a)
+				break;
+		}
+		if (*a == '\0')
+			return count;
+		++count;
+	}
+
+	return count;
+}
+#endif
+
+#ifndef __HAVE_ARCH_STRPBRK
+/**
+ * strpbrk - Find the first occurrence of a set of characters
+ * @cs: The string to be searched
+ * @ct: The characters to search for
+ */
+char * strpbrk(const char * cs,const char * ct)
+{
+	const char *sc1,*sc2;
+
+	for( sc1 = cs; *sc1 != '\0'; ++sc1) {
+		for( sc2 = ct; *sc2 != '\0'; ++sc2) {
+			if (*sc1 == *sc2)
+				return (char *) sc1;
+		}
+	}
+	return NULL;
+}
+#endif
+
+#ifndef __HAVE_ARCH_STRTOK
+/**
+ * strtok - Split a string into tokens
+ * @s: The string to be searched
+ * @ct: The characters to search for
+ *
+ * WARNING: strtok is deprecated, use strsep instead.
+ */
+char * strtok(char * s,const char * ct)
+{
+	char *sbegin, *send;
+
+	sbegin  = s ? s : ___strtok;
+	if (!sbegin) {
+		return NULL;
+	}
+	sbegin += strspn(sbegin,ct);
+	if (*sbegin == '\0') {
+		___strtok = NULL;
+		return( NULL );
+	}
+	send = strpbrk( sbegin, ct);
+	if (send && *send != '\0')
+		*send++ = '\0';
+	___strtok = send;
+	return (sbegin);
+}
+#endif
+
+#ifndef __HAVE_ARCH_STRSEP
+/**
+ * strsep - Split a string into tokens
+ * @s: The string to be searched
+ * @ct: The characters to search for
+ *
+ * strsep() updates @s to point after the token, ready for the next call.
+ *
+ * It returns empty tokens, too, behaving exactly like the libc function
+ * of that name. In fact, it was stolen from glibc2 and de-fancy-fied.
+ * Same semantics, slimmer shape. ;)
+ */
+char * strsep(char **s, const char *ct)
+{
+	char *sbegin = *s, *end;
+
+	if (sbegin == NULL)
+		return NULL;
+
+	end = strpbrk(sbegin, ct);
+	if (end)
+		*end++ = '\0';
+	*s = end;
+
+	return sbegin;
+}
+#endif
+
+#ifndef __HAVE_ARCH_STRSWAB
+/**
+ * strswab - swap adjacent even and odd bytes in %NUL-terminated string
+ * s: address of the string
+ *
+ * returns the address of the swapped string or NULL on error. If
+ * string length is odd, last byte is untouched.
+ */
+char *strswab(const char *s)
+{
+	char *p, *q;
+
+	if ((NULL == s) || ('\0' == *s)) {
+		return (NULL);
+	}
+
+	for (p=(char *)s, q=p+1; (*p != '\0') && (*q != '\0'); p+=2, q+=2) {
+		char  tmp;
+
+		tmp = *p;
+		*p  = *q;
+		*q  = tmp;
+	}
+
+	return (char *) s;
+}
+#endif
+
+#ifndef __HAVE_ARCH_MEMSET
+/**
+ * memset - Fill a region of memory with the given value
+ * @s: Pointer to the start of the area.
+ * @c: The byte to fill the area with
+ * @count: The size of the area.
+ *
+ * Do not use memset() to access IO space, use memset_io() instead.
+ */
+void * memset(void * s,int c,size_t count)
+{
+	unsigned long *sl = (unsigned long *) s;
+	unsigned long cl = 0;
+	char *s8;
+	int i;
+
+	/* do it one word at a time (32 bits or 64 bits) while possible */
+	if ( ((ulong)s & (sizeof(*sl) - 1)) == 0) {
+		for (i = 0; i < sizeof(*sl); i++) {
+			cl <<= 8;
+			cl |= c & 0xff;
+		}
+		while (count >= sizeof(*sl)) {
+			*sl++ = cl;
+			count -= sizeof(*sl);
+		}
+	}
+	/* fill 8 bits at a time */
+	s8 = (char *)sl;
+	while (count--)
+		*s8++ = c;
+
+	return s;
+}
+#endif
+
+#ifndef __HAVE_ARCH_BCOPY
+/**
+ * bcopy - Copy one area of memory to another
+ * @src: Where to copy from
+ * @dest: Where to copy to
+ * @count: The size of the area.
+ *
+ * Note that this is the same as memcpy(), with the arguments reversed.
+ * memcpy() is the standard, bcopy() is a legacy BSD function.
+ *
+ * You should not use this function to access IO space, use memcpy_toio()
+ * or memcpy_fromio() instead.
+ */
+char * bcopy(const char * src, char * dest, int count)
+{
+	char *tmp = dest;
+
+	while (count--)
+		*tmp++ = *src++;
+
+	return dest;
+}
+#endif
+
+#ifndef __HAVE_ARCH_MEMCPY
+/**
+ * memcpy - Copy one area of memory to another
+ * @dest: Where to copy to
+ * @src: Where to copy from
+ * @count: The size of the area.
+ *
+ * You should not use this function to access IO space, use memcpy_toio()
+ * or memcpy_fromio() instead.
+ */
+void * memcpy(void *dest, const void *src, size_t count)
+{
+	unsigned long *dl = (unsigned long *)dest, *sl = (unsigned long *)src;
+	char *d8, *s8;
+
+	/* while all data is aligned (common case), copy a word at a time */
+	if ( (((ulong)dest | (ulong)src) & (sizeof(*dl) - 1)) == 0) {
+		while (count >= sizeof(*dl)) {
+			*dl++ = *sl++;
+			count -= sizeof(*dl);
+		}
+	}
+	/* copy the reset one byte at a time */
+	d8 = (char *)dl;
+	s8 = (char *)sl;
+	while (count--)
+		*d8++ = *s8++;
+
+	return dest;
+}
+#endif
+
+#ifndef __HAVE_ARCH_MEMMOVE
+/**
+ * memmove - Copy one area of memory to another
+ * @dest: Where to copy to
+ * @src: Where to copy from
+ * @count: The size of the area.
+ *
+ * Unlike memcpy(), memmove() copes with overlapping areas.
+ */
+void * memmove(void * dest,const void *src,size_t count)
+{
+	char *tmp, *s;
+
+	if (dest <= src) {
+		tmp = (char *) dest;
+		s = (char *) src;
+		while (count--)
+			*tmp++ = *s++;
+		}
+	else {
+		tmp = (char *) dest + count;
+		s = (char *) src + count;
+		while (count--)
+			*--tmp = *--s;
+		}
+
+	return dest;
+}
+#endif
+
+#ifndef __HAVE_ARCH_MEMCMP
+/**
+ * memcmp - Compare two areas of memory
+ * @cs: One area of memory
+ * @ct: Another area of memory
+ * @count: The size of the area.
+ */
+int memcmp(const void * cs,const void * ct,size_t count)
+{
+	const unsigned char *su1, *su2;
+	int res = 0;
+
+	for( su1 = cs, su2 = ct; 0 < count; ++su1, ++su2, count--)
+		if ((res = *su1 - *su2) != 0)
+			break;
+	return res;
+}
+#endif
+
+#ifndef __HAVE_ARCH_MEMSCAN
+/**
+ * memscan - Find a character in an area of memory.
+ * @addr: The memory area
+ * @c: The byte to search for
+ * @size: The size of the area.
+ *
+ * returns the address of the first occurrence of @c, or 1 byte past
+ * the area if @c is not found
+ */
+void * memscan(void * addr, int c, size_t size)
+{
+	unsigned char * p = (unsigned char *) addr;
+
+	while (size) {
+		if (*p == c)
+			return (void *) p;
+		p++;
+		size--;
+	}
+	return (void *) p;
+}
+#endif
+
+#ifndef __HAVE_ARCH_STRSTR
+/**
+ * strstr - Find the first substring in a %NUL terminated string
+ * @s1: The string to be searched
+ * @s2: The string to search for
+ */
+char * strstr(const char * s1,const char * s2)
+{
+	int l1, l2;
+
+	l2 = strlen(s2);
+	if (!l2)
+		return (char *) s1;
+	l1 = strlen(s1);
+	while (l1 >= l2) {
+		l1--;
+		if (!memcmp(s1,s2,l2))
+			return (char *) s1;
+		s1++;
+	}
+	return NULL;
+}
+#endif
+
+#ifndef __HAVE_ARCH_MEMCHR
+/**
+ * memchr - Find a character in an area of memory.
+ * @s: The memory area
+ * @c: The byte to search for
+ * @n: The size of the area.
+ *
+ * returns the address of the first occurrence of @c, or %NULL
+ * if @c is not found
+ */
+void *memchr(const void *s, int c, size_t n)
+{
+	const unsigned char *p = s;
+	while (n-- != 0) {
+		if ((unsigned char)c == *p++) {
+			return (void *)(p-1);
+		}
+	}
+	return NULL;
+}
+
+#endif
diff --git a/linux-bsp/asm-study/yaffs2/common/string.h b/linux-bsp/asm-study/yaffs2/common/string.h
new file mode 100644
index 0000000..398ca61
--- /dev/null
+++ b/linux-bsp/asm-study/yaffs2/common/string.h
@@ -0,0 +1,86 @@
+#ifndef _LINUX_STRING_H_
+#define _LINUX_STRING_H_
+
+#include <types.h>	/* for size_t */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+extern char * ___strtok;
+extern char * strpbrk(const char *,const char *);
+extern char * strtok(char *,const char *);
+extern char * strsep(char **,const char *);
+extern __kernel_size_t strspn(const char *,const char *);
+
+
+/*
+ * Include machine specific inline routines
+ */
+#ifndef __HAVE_ARCH_STRCPY
+extern char * strcpy(char *,const char *);
+#endif
+#ifndef __HAVE_ARCH_STRNCPY
+extern char * strncpy(char *,const char *, __kernel_size_t);
+#endif
+#ifndef __HAVE_ARCH_STRCAT
+extern char * strcat(char *, const char *);
+#endif
+#ifndef __HAVE_ARCH_STRNCAT
+extern char * strncat(char *, const char *, __kernel_size_t);
+#endif
+#ifndef __HAVE_ARCH_STRCMP
+extern int strcmp(const char *,const char *);
+#endif
+#ifndef __HAVE_ARCH_STRNCMP
+extern int strncmp(const char *,const char *,__kernel_size_t);
+#endif
+#if 0 /* not used - was: #ifndef __HAVE_ARCH_STRNICMP */
+extern int strnicmp(const char *, const char *, __kernel_size_t);
+#endif
+#ifndef __HAVE_ARCH_STRCHR
+extern char * strchr(const char *,int);
+#endif
+#ifndef __HAVE_ARCH_STRRCHR
+extern char * strrchr(const char *,int);
+#endif
+#ifndef __HAVE_ARCH_STRSTR
+extern char * strstr(const char *,const char *);
+#endif
+#ifndef __HAVE_ARCH_STRLEN
+extern __kernel_size_t strlen(const char *);
+#endif
+#ifndef __HAVE_ARCH_STRNLEN
+extern __kernel_size_t strnlen(const char *,__kernel_size_t);
+#endif
+#ifndef __HAVE_ARCH_STRDUP
+extern char * strdup(const char *);
+#endif
+#ifndef __HAVE_ARCH_STRSWAB
+extern char * strswab(const char *);
+#endif
+
+#ifndef __HAVE_ARCH_MEMSET
+extern void * memset(void *,int,__kernel_size_t);
+#endif
+#ifndef __HAVE_ARCH_MEMCPY
+extern void * memcpy(void *,const void *,__kernel_size_t);
+#endif
+#ifndef __HAVE_ARCH_MEMMOVE
+extern void * memmove(void *,const void *,__kernel_size_t);
+#endif
+#ifndef __HAVE_ARCH_MEMSCAN
+extern void * memscan(void *,int,__kernel_size_t);
+#endif
+#ifndef __HAVE_ARCH_MEMCMP
+extern int memcmp(const void *,const void *,__kernel_size_t);
+#endif
+#ifndef __HAVE_ARCH_MEMCHR
+extern void * memchr(const void *,int,__kernel_size_t);
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _LINUX_STRING_H_ */
diff --git a/linux-bsp/asm-study/yaffs2/common/types.h b/linux-bsp/asm-study/yaffs2/common/types.h
new file mode 100644
index 0000000..e2fd660
--- /dev/null
+++ b/linux-bsp/asm-study/yaffs2/common/types.h
@@ -0,0 +1,99 @@
+#ifndef _LINUX_TYPES_H
+#define _LINUX_TYPES_H
+
+
+#undef NULL
+#if defined(__cplusplus)
+#define NULL 0
+#else
+#define NULL ((void *)0)
+#endif
+
+/* bsd */
+typedef unsigned char u_char;
+typedef unsigned short u_short;
+typedef unsigned int u_int;
+typedef unsigned long u_long;
+
+/* sysv */
+typedef unsigned char unchar;
+typedef unsigned short ushort;
+typedef unsigned int uint;
+typedef unsigned long ulong;
+
+/*
+ * __xx is ok: it doesn't pollute the POSIX namespace. Use these in the
+ * header files exported to user space
+ */
+typedef __signed__ char __s8;
+typedef unsigned char __u8;
+typedef __signed__ short __s16;
+typedef unsigned short __u16;
+typedef __signed__ int __s32;
+typedef unsigned int __u32;
+#if defined(__GNUC__)
+__extension__ typedef __signed__ long long __s64;
+__extension__ typedef unsigned long long __u64;
+#endif
+
+typedef signed char s8;
+typedef unsigned char u8;
+typedef signed short s16;
+typedef unsigned short u16;
+typedef signed int s32;
+typedef unsigned int u32;
+typedef signed long long s64;
+typedef unsigned long long u64; 
+
+typedef unsigned int __kernel_size_t;
+typedef int __kernel_ssize_t;
+typedef int __kernel_ptrdiff_t;
+typedef long __kernel_off_t;
+typedef long long __kernel_loff_t;
+typedef unsigned short __kernel_dev_t;
+typedef unsigned short __kernel_mode_t;
+
+
+typedef __kernel_dev_t dev_t;
+typedef __kernel_mode_t mode_t;
+typedef __kernel_off_t off_t;
+typedef __kernel_loff_t loff_t;
+
+#ifndef _PTRDIFF_T
+#define _PTRDIFF_T
+typedef __kernel_ptrdiff_t ptrdiff_t;
+#endif 
+
+#ifndef _SIZE_T
+#define _SIZE_T
+typedef __kernel_size_t size_t;
+#endif
+
+#ifndef _SSIZE_T
+#define _SSIZE_T
+typedef __kernel_ssize_t ssize_t;
+#endif
+
+#ifndef __BIT_TYPES_DEFINED__
+#define __BIT_TYPES_DEFINED__
+
+typedef __u8 u_int8_t;
+typedef __s8 int8_t;
+typedef __u16 u_int16_t;
+typedef __s16 int16_t;
+typedef __u32 u_int32_t;
+typedef __s32 int32_t;
+
+#endif                          /* !(__BIT_TYPES_DEFINED__) */
+
+typedef __u8 uint8_t;
+typedef __u16 uint16_t;
+typedef __u32 uint32_t;
+
+#if defined(__GNUC__) && !defined(__STRICT_ANSI__)
+typedef __u64 uint64_t;
+typedef __u64 u_int64_t;
+typedef __s64 int64_t;
+#endif
+
+#endif                          /* _LINUX_TYPES_H */
diff --git a/linux-bsp/asm-study/yaffs2/makefile b/linux-bsp/asm-study/yaffs2/makefile
new file mode 100644
index 0000000..32c2808
--- /dev/null
+++ b/linux-bsp/asm-study/yaffs2/makefile
@@ -0,0 +1,104 @@
+
+# ***********************************************************************
+# *        File:  makefile
+# *     Version:  1.0.0
+# *   Copyright:  2011 (c) Guo Wenxue <guowenxue@gmail.com>
+# * Description:  Makefile used to cross compile the ASM source code
+# *   ChangeLog:  1, Release initial version on "Sun Mar 20 18:41:04 CST 2011"
+# *
+# ***********************************************************************
+#
+
+APP_NAME=bootstrap
+INST_PATH=/tftp
+SRC_TOP=$(CURDIR)
+
+OBJS_MAIN := bootstrap.o start.o 
+OBJS_BSP += ${SRC_TOP}/bsp/*.o
+OBJS_COMMON += ${SRC_TOP}/common/*.o
+OBJS_YAFFS2 += ${SRC_TOP}/yaffs2/*.o
+
+CFLAGS+=-I${SRC_TOP}/common
+CFLAGS+=-I${SRC_TOP}/bsp
+CFLAGS+=-I${SRC_TOP}/yaffs2 
+
+# Set the stack top base address here
+TEXT_BASE=0x31000000
+STACK_BASE=0x31010000
+MALLOC_SIZE=0x100000
+CFLAGS+=-DTEXT_BASE=$(TEXT_BASE) -DSTACK_BASE=${STACK_BASE} -DCONFIG_SYS_MALLOC_LEN=${MALLOC_SIZE}
+
+CFLAGS+=-DDEBUG
+
+gccincdir := $(shell $(CC) -print-file-name=include)
+CFLAGS += -ffreestanding -nostdinc -isystem $(gccincdir) -pipe 
+CFLAGS+= -fno-strict-aliasing  -fno-common -ffixed-r8 -msoft-float 
+CFLAGS+=-march=armv4t -Wall -Wno-unused -Wstrict-prototypes -fno-stack-protector
+CFLAGS += -fno-builtin  
+LDFLAGS=-Bstatic -T$(APP_NAME).lds -Ttext $(TEXT_BASE)
+AFLAGS := $(CFLAGS) -D__ASSEMBLY__
+export CFLAGS
+export AFLAGS
+
+#CFLAGS+=-Os -D__KERNEL__ -DCONFIG_ARM -D__ARM__ 
+PLATFORM_LIBS += -L $(shell dirname `$(CC) $(CFLAGS) -print-libgcc-file-name`) -lgcc
+#PLATFORM_LIBS += -L/opt/buildroot-2011.11/arm920t/usr/arm-unknown-linux-uclibcgnueabi/sysroot/usr/lib/ -lc 
+
+CROSS_COMPILE=/opt/xtools/arm920t/bin/arm-linux-
+AS  = $(CROSS_COMPILE)as
+LD  = $(CROSS_COMPILE)ld
+CC  = $(CROSS_COMPILE)gcc
+CPP = $(CC) -E
+AR  = $(CROSS_COMPILE)ar
+NM  = $(CROSS_COMPILE)nm
+LDR = $(CROSS_COMPILE)ldr
+STRIP   = $(CROSS_COMPILE)strip
+OBJCOPY = $(CROSS_COMPILE)objcopy
+OBJDUMP = $(CROSS_COMPILE)objdump
+RANLIB  = $(CROSS_COMPILE)RANLIB
+
+export  CROSS_COMPILE AS LD CC CPP AR NM STRIP OBJCOPY OBJDUMP CFLAGS
+
+ALL: clean bsp_lib common_lib yaffs2_lib ${OBJS_MAIN} 
+	echo ${OBJS_BSP}
+	cd $(SRC_TOP) 
+	${LD} $(LDFLAGS) \
+	--start-group ${OBJS_BSP} ${OBJS_COMMON} ${OBJS_YAFFS2} $(OBJS_MAIN) \
+	--end-group $(PLATFORM_LIBS) \
+	-Map $(APP_NAME).map  -o $(APP_NAME).elf
+	${OBJCOPY} -O binary $(APP_NAME).elf $(APP_NAME).bin
+	@chmod 777 $(APP_NAME).bin
+	@rm -f *.elf *.o
+	@make install
+
+bsp_lib:
+	@make -C bsp
+
+common_lib:
+	@make -C common
+
+yaffs2_lib:
+	@make -C yaffs2
+
+%.o: %.S
+	 $(CC) $(AFLAGS) -c -o $@ $<
+
+%.o: %.c
+	 $(CC) $(CFLAGS) -c -o $@ $<
+
+install: $(APP_NAME).bin
+	cp $(APP_NAME).bin $(INST_PATH) -f 
+
+clean:
+	@find $(OBJTREE) -type f \
+			\( -name 'core' -o -name '*.bak' -o -name '*~' -o -name .depend \
+			-o -name '*.o'  -o -name '*.a' -o -name '*.elf' \) -print \
+			| xargs rm -f
+	@rm -f $(APP_NAME).bin
+	@rm -f $(APP_NAME).map
+	@make clean -C yaffs2
+
+distclean clear: clean
+	@rm -f cscope.* tags
+
+
diff --git a/linux-bsp/asm-study/yaffs2/start.S b/linux-bsp/asm-study/yaffs2/start.S
new file mode 100644
index 0000000..49e5040
--- /dev/null
+++ b/linux-bsp/asm-study/yaffs2/start.S
@@ -0,0 +1,60 @@
+
+/********************************************************************************************
+ *        File:  start.S - Startup Code for ARM920 CPU-core
+ *     Version:  1.0.0
+ *   Copyright:  2011 (c) Guo Wenxue <guowenxue@gmail.com>
+ * Description:  When system power up, the CPU will comes here to excute the first code here.
+ *   ChangeLog:  1, Release initial version on "Tue Jul 12 16:43:18 CST 2011"
+ *
+ *******************************************************************************************/
+
+
+/*
+ *************************************************************************
+ *
+ * Jump vector table as in table 3.1 in [1]
+ *
+ *************************************************************************
+ */
+
+.globl _start
+_start:	b	start_code
+
+_TEXT_BASE:
+    .word   TEXT_BASE 
+    
+.globl _armboot_start
+_armboot_start:
+    .word _start
+
+/*
+ * These are defined in the board-specific linker script.
+ */
+.globl _bss_start
+_bss_start:
+	.word __bss_start
+
+.globl _bss_end
+_bss_end:
+	.word _end
+
+start_code:
+	/* Set up the stack	*/
+stack_setup:
+	ldr	r0, =TEXT_BASE		/* upper 128 KiB: relocated uboot   */
+	sub	r0, r0, #CONFIG_SYS_MALLOC_LEN	/* malloc area              */
+	sub	sp, r0, #12		/* leave 3 words for abort-stack    */
+	bic	sp, sp, #7		/* 8-byte alignment for ABI compliance */
+
+clear_bss:
+	ldr	r0, _bss_start		/* find start of bss segment        */
+	ldr	r1, _bss_end		/* stop here                        */
+	mov	r2, #0x00000000		/* clear                            */
+
+clbss_l:str	r2, [r0]		/* clear loop...                    */
+	add	r0, r0, #4
+	cmp	r0, r1
+	ble	clbss_l
+
+    bl  bootstrap_main
+
diff --git a/linux-bsp/asm-study/yaffs2/yaffs2/makefile b/linux-bsp/asm-study/yaffs2/yaffs2/makefile
new file mode 100644
index 0000000..78e9641
--- /dev/null
+++ b/linux-bsp/asm-study/yaffs2/yaffs2/makefile
@@ -0,0 +1,97 @@
+#*********************************************************************************
+#      Copyright:  (C) 2012 CoherentPlus Sdn. Bhd.
+#                  All rights reserved.
+#
+#       Filename:  Makefile
+#    Description:  This is the common subdir Makefile which to compile all the C
+#                  source code to object files and then generate the shared or 
+#                  static library named lib$(FOLDER_NAME).a orlib $(FOLDER_NAME).so,
+#                  which depends on the variable $LINK_MODE.
+#                      
+#        Version:  1.0.0(10/08/2011~)
+#                  Author:  Guo Wenxue <guowenxue@gmail.com>
+#      ChangeLog:  1, Release initial version on "10/08/2011 01:29:33 AM"
+#                       
+#********************************************************************************/
+
+PWD=$(shell pwd)
+LOCAL_COMPILE=YES
+LINK_MODE=STATIC
+
+#If wanna compile in the subdir, not called by top makefile, uncomment it
+ifneq (${TOP_COMPILE}, YES) 
+LOCAL_COMPILE=YES
+endif
+
+LIBNAME=$(shell basename ${PWD})
+STALIB=lib${LIBNAME}.a
+DYNLIB=lib${LIBNAME}.so
+
+VPATH= .
+SRCS = $(wildcard ${VPATH}/*.c)
+OBJS = $(patsubst %.c,%.o,$(SRCS))
+
+#======================================================
+#  ---> Doesn't call by top makefile, compile by local
+#======================================================
+ifeq (${LOCAL_COMPILE}, YES)
+ARCH?=arm920t
+#ARCH?=i386
+CFLAGS+=-fPIC
+TMP=$(shell echo $(ARCH) | tr "[A-Z]" "[a-z]")
+ifneq (,$(filter i386,$(TMP)))
+    CROSS_COMPILE=
+else
+    CROSS_COMPILE=/opt/xtools/arm920t/bin/arm-linux-
+endif
+
+PRJDIR?=$(shell pwd)
+CFLAGS+=-I${PRJDIR}
+CC = ${CROSS_COMPILE}gcc
+AR = ${CROSS_COMPILE}ar
+
+endif #End local compile
+
+ifeq ("${LINK_MODE}", "STATIC")
+	LIBS = ${STALIB} 
+else 
+	LIBS=${DYNLIB}
+endif
+
+all: entry ${LIBS} install
+
+entry: 
+	@echo " ";
+	@echo " =========================================================";
+	@echo " **     Compile subdir ${LIBNAME} for ${ARCH}             ";
+	@echo " =========================================================";
+
+#$(LD) -g --relocatable $(OBJS) -o lib${LIBNAME}.o
+${STALIB}:	$(OBJS) 
+	$(AR) -rcu $@ $(OBJS)
+
+${DYNLIB}:   $(OBJS) 
+	$(CC) -fPIC -shared -o $@ $(OBJS)
+
+%.o : %.c
+	$(CC) -c $< $(CFLAGS)
+
+tag: 
+	@ctags --c-kinds=+defglmnstuvx --langmap=c:.c.h.ho.hem.het.hec.hev.him.hit.hic.hiv -R .  
+	@cscope -Rbq
+
+install:
+	@if [ ! -z "${LIBS_PATH}" ] ; then \
+		mkdir -p ${LIBS_PATH} ; \
+		cp ${LIBS} ${LIBS_PATH}; \
+	fi;
+
+
+clean:
+	@rm -f *.o
+	@rm -rf *.gdb *.a *.so
+
+distclean: clean
+	@rm -f  tags cscope*
+
+.PHONY: clean entry
diff --git a/linux-bsp/asm-study/yaffs2/yaffs2/yaffs_allocator.c b/linux-bsp/asm-study/yaffs2/yaffs2/yaffs_allocator.c
new file mode 100644
index 0000000..c8f2861
--- /dev/null
+++ b/linux-bsp/asm-study/yaffs2/yaffs2/yaffs_allocator.c
@@ -0,0 +1,357 @@
+/*
+ * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
+ *
+ * Copyright (C) 2002-2011 Aleph One Ltd.
+ *   for Toby Churchill Ltd and Brightstar Engineering
+ *
+ * Created by Charles Manning <charles@aleph1.co.uk>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include "yaffs_allocator.h"
+#include "yaffs_guts.h"
+#include "yaffs_trace.h"
+#include "yportenv.h"
+
+/*
+ * Each entry in yaffs_tnode_list and yaffs_obj_list hold blocks
+ * of approx 100 objects that are themn allocated singly.
+ * This is basically a simplified slab allocator.
+ *
+ * We don't use the Linux slab allocator because slab does not allow
+ * us to dump all the objects in one hit when we do a umount and tear
+ * down  all the tnodes and objects. slab requires that we first free
+ * the individual objects.
+ *
+ * Once yaffs has been mainlined I shall try to motivate for a change
+ * to slab to provide the extra features we need here.
+ */
+
+struct yaffs_tnode_list {
+	struct yaffs_tnode_list *next;
+	struct yaffs_tnode *tnodes;
+};
+
+struct yaffs_obj_list {
+	struct yaffs_obj_list *next;
+	struct yaffs_obj *objects;
+};
+
+struct yaffs_allocator {
+	int n_tnodes_created;
+	struct yaffs_tnode *free_tnodes;
+	int n_free_tnodes;
+	struct yaffs_tnode_list *alloc_tnode_list;
+
+	int n_obj_created;
+	struct list_head free_objs;
+	int n_free_objects;
+
+	struct yaffs_obj_list *allocated_obj_list;
+};
+
+static void yaffs_deinit_raw_tnodes(struct yaffs_dev *dev)
+{
+	struct yaffs_allocator *allocator =
+	    (struct yaffs_allocator *)dev->allocator;
+	struct yaffs_tnode_list *tmp;
+
+	if (!allocator) {
+		BUG();
+		return;
+	}
+
+	while (allocator->alloc_tnode_list) {
+		tmp = allocator->alloc_tnode_list->next;
+
+		kfree(allocator->alloc_tnode_list->tnodes);
+		kfree(allocator->alloc_tnode_list);
+		allocator->alloc_tnode_list = tmp;
+	}
+
+	allocator->free_tnodes = NULL;
+	allocator->n_free_tnodes = 0;
+	allocator->n_tnodes_created = 0;
+}
+
+static void yaffs_init_raw_tnodes(struct yaffs_dev *dev)
+{
+	struct yaffs_allocator *allocator = dev->allocator;
+
+	if (!allocator) {
+		BUG();
+		return;
+	}
+
+	allocator->alloc_tnode_list = NULL;
+	allocator->free_tnodes = NULL;
+	allocator->n_free_tnodes = 0;
+	allocator->n_tnodes_created = 0;
+}
+
+static int yaffs_create_tnodes(struct yaffs_dev *dev, int n_tnodes)
+{
+	struct yaffs_allocator *allocator =
+	    (struct yaffs_allocator *)dev->allocator;
+	int i;
+	struct yaffs_tnode *new_tnodes;
+	u8 *mem;
+	struct yaffs_tnode *curr;
+	struct yaffs_tnode *next;
+	struct yaffs_tnode_list *tnl;
+
+	if (!allocator) {
+		BUG();
+		return YAFFS_FAIL;
+	}
+
+	if (n_tnodes < 1)
+		return YAFFS_OK;
+
+	/* make these things */
+	new_tnodes = kmalloc(n_tnodes * dev->tnode_size, GFP_NOFS);
+	mem = (u8 *) new_tnodes;
+
+	if (!new_tnodes) {
+		yaffs_trace(YAFFS_TRACE_ERROR,
+			"yaffs: Could not allocate Tnodes");
+		return YAFFS_FAIL;
+	}
+
+	/* New hookup for wide tnodes */
+	for (i = 0; i < n_tnodes - 1; i++) {
+		curr = (struct yaffs_tnode *)&mem[i * dev->tnode_size];
+		next = (struct yaffs_tnode *)&mem[(i + 1) * dev->tnode_size];
+		curr->internal[0] = next;
+	}
+
+	curr = (struct yaffs_tnode *)&mem[(n_tnodes - 1) * dev->tnode_size];
+	curr->internal[0] = allocator->free_tnodes;
+	allocator->free_tnodes = (struct yaffs_tnode *)mem;
+
+	allocator->n_free_tnodes += n_tnodes;
+	allocator->n_tnodes_created += n_tnodes;
+
+	/* Now add this bunch of tnodes to a list for freeing up.
+	 * NB If we can't add this to the management list it isn't fatal
+	 * but it just means we can't free this bunch of tnodes later.
+	 */
+	tnl = kmalloc(sizeof(struct yaffs_tnode_list), GFP_NOFS);
+	if (!tnl) {
+		yaffs_trace(YAFFS_TRACE_ERROR,
+			"Could not add tnodes to management list");
+		return YAFFS_FAIL;
+	} else {
+		tnl->tnodes = new_tnodes;
+		tnl->next = allocator->alloc_tnode_list;
+		allocator->alloc_tnode_list = tnl;
+	}
+
+	yaffs_trace(YAFFS_TRACE_ALLOCATE, "Tnodes added");
+
+	return YAFFS_OK;
+}
+
+struct yaffs_tnode *yaffs_alloc_raw_tnode(struct yaffs_dev *dev)
+{
+	struct yaffs_allocator *allocator =
+	    (struct yaffs_allocator *)dev->allocator;
+	struct yaffs_tnode *tn = NULL;
+
+	if (!allocator) {
+		BUG();
+		return NULL;
+	}
+
+	/* If there are none left make more */
+	if (!allocator->free_tnodes)
+		yaffs_create_tnodes(dev, YAFFS_ALLOCATION_NTNODES);
+
+	if (allocator->free_tnodes) {
+		tn = allocator->free_tnodes;
+		allocator->free_tnodes = allocator->free_tnodes->internal[0];
+		allocator->n_free_tnodes--;
+	}
+
+	return tn;
+}
+
+/* FreeTnode frees up a tnode and puts it back on the free list */
+void yaffs_free_raw_tnode(struct yaffs_dev *dev, struct yaffs_tnode *tn)
+{
+	struct yaffs_allocator *allocator = dev->allocator;
+
+	if (!allocator) {
+		BUG();
+		return;
+	}
+
+	if (tn) {
+		tn->internal[0] = allocator->free_tnodes;
+		allocator->free_tnodes = tn;
+		allocator->n_free_tnodes++;
+	}
+	dev->checkpoint_blocks_required = 0;	/* force recalculation */
+}
+
+/*--------------- yaffs_obj alloaction ------------------------
+ *
+ * Free yaffs_objs are stored in a list using obj->siblings.
+ * The blocks of allocated objects are stored in a linked list.
+ */
+
+static void yaffs_init_raw_objs(struct yaffs_dev *dev)
+{
+	struct yaffs_allocator *allocator = dev->allocator;
+
+	if (!allocator) {
+		BUG();
+		return;
+	}
+
+	allocator->allocated_obj_list = NULL;
+	INIT_LIST_HEAD(&allocator->free_objs);
+	allocator->n_free_objects = 0;
+}
+
+static void yaffs_deinit_raw_objs(struct yaffs_dev *dev)
+{
+	struct yaffs_allocator *allocator = dev->allocator;
+	struct yaffs_obj_list *tmp;
+
+	if (!allocator) {
+		BUG();
+		return;
+	}
+
+	while (allocator->allocated_obj_list) {
+		tmp = allocator->allocated_obj_list->next;
+		kfree(allocator->allocated_obj_list->objects);
+		kfree(allocator->allocated_obj_list);
+		allocator->allocated_obj_list = tmp;
+	}
+
+	INIT_LIST_HEAD(&allocator->free_objs);
+	allocator->n_free_objects = 0;
+	allocator->n_obj_created = 0;
+}
+
+static int yaffs_create_free_objs(struct yaffs_dev *dev, int n_obj)
+{
+	struct yaffs_allocator *allocator = dev->allocator;
+	int i;
+	struct yaffs_obj *new_objs;
+	struct yaffs_obj_list *list;
+
+	if (!allocator) {
+		BUG();
+		return YAFFS_FAIL;
+	}
+
+	if (n_obj < 1)
+		return YAFFS_OK;
+
+	/* make these things */
+	new_objs = kmalloc(n_obj * sizeof(struct yaffs_obj), GFP_NOFS);
+	list = kmalloc(sizeof(struct yaffs_obj_list), GFP_NOFS);
+
+	if (!new_objs || !list) {
+		kfree(new_objs);
+		new_objs = NULL;
+		kfree(list);
+		list = NULL;
+		yaffs_trace(YAFFS_TRACE_ALLOCATE,
+			"Could not allocate more objects");
+		return YAFFS_FAIL;
+	}
+
+	/* Hook them into the free list */
+	for (i = 0; i < n_obj; i++)
+		list_add(&new_objs[i].siblings, &allocator->free_objs);
+
+	allocator->n_free_objects += n_obj;
+	allocator->n_obj_created += n_obj;
+
+	/* Now add this bunch of Objects to a list for freeing up. */
+
+	list->objects = new_objs;
+	list->next = allocator->allocated_obj_list;
+	allocator->allocated_obj_list = list;
+
+	return YAFFS_OK;
+}
+
+struct yaffs_obj *yaffs_alloc_raw_obj(struct yaffs_dev *dev)
+{
+	struct yaffs_obj *obj = NULL;
+	struct list_head *lh;
+	struct yaffs_allocator *allocator = dev->allocator;
+
+	if (!allocator) {
+		BUG();
+		return obj;
+	}
+
+	/* If there are none left make more */
+	if (list_empty(&allocator->free_objs))
+		yaffs_create_free_objs(dev, YAFFS_ALLOCATION_NOBJECTS);
+
+	if (!list_empty(&allocator->free_objs)) {
+		lh = allocator->free_objs.next;
+		obj = list_entry(lh, struct yaffs_obj, siblings);
+		list_del_init(lh);
+		allocator->n_free_objects--;
+	}
+
+	return obj;
+}
+
+void yaffs_free_raw_obj(struct yaffs_dev *dev, struct yaffs_obj *obj)
+{
+
+	struct yaffs_allocator *allocator = dev->allocator;
+
+	if (!allocator) {
+		BUG();
+		return;
+	}
+
+	/* Link into the free list. */
+	list_add(&obj->siblings, &allocator->free_objs);
+	allocator->n_free_objects++;
+}
+
+void yaffs_deinit_raw_tnodes_and_objs(struct yaffs_dev *dev)
+{
+
+	if (!dev->allocator) {
+		BUG();
+		return;
+	}
+
+	yaffs_deinit_raw_tnodes(dev);
+	yaffs_deinit_raw_objs(dev);
+	kfree(dev->allocator);
+	dev->allocator = NULL;
+}
+
+void yaffs_init_raw_tnodes_and_objs(struct yaffs_dev *dev)
+{
+	struct yaffs_allocator *allocator;
+
+	if (dev->allocator) {
+		BUG();
+		return;
+	}
+
+	allocator = kmalloc(sizeof(struct yaffs_allocator), GFP_NOFS);
+	if (allocator) {
+		dev->allocator = allocator;
+		yaffs_init_raw_tnodes(dev);
+		yaffs_init_raw_objs(dev);
+	}
+}
+
diff --git a/linux-bsp/asm-study/yaffs2/yaffs2/yaffs_allocator.h b/linux-bsp/asm-study/yaffs2/yaffs2/yaffs_allocator.h
new file mode 100644
index 0000000..a8cc322
--- /dev/null
+++ b/linux-bsp/asm-study/yaffs2/yaffs2/yaffs_allocator.h
@@ -0,0 +1,30 @@
+/*
+ * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
+ *
+ * Copyright (C) 2002-2011 Aleph One Ltd.
+ *   for Toby Churchill Ltd and Brightstar Engineering
+ *
+ * Created by Charles Manning <charles@aleph1.co.uk>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 2.1 as
+ * published by the Free Software Foundation.
+ *
+ * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
+ */
+
+#ifndef __YAFFS_ALLOCATOR_H__
+#define __YAFFS_ALLOCATOR_H__
+
+#include "yaffs_guts.h"
+
+void yaffs_init_raw_tnodes_and_objs(struct yaffs_dev *dev);
+void yaffs_deinit_raw_tnodes_and_objs(struct yaffs_dev *dev);
+
+struct yaffs_tnode *yaffs_alloc_raw_tnode(struct yaffs_dev *dev);
+void yaffs_free_raw_tnode(struct yaffs_dev *dev, struct yaffs_tnode *tn);
+
+struct yaffs_obj *yaffs_alloc_raw_obj(struct yaffs_dev *dev);
+void yaffs_free_raw_obj(struct yaffs_dev *dev, struct yaffs_obj *obj);
+
+#endif
diff --git a/linux-bsp/asm-study/yaffs2/yaffs2/yaffs_attribs.c b/linux-bsp/asm-study/yaffs2/yaffs2/yaffs_attribs.c
new file mode 100644
index 0000000..3d778f2
--- /dev/null
+++ b/linux-bsp/asm-study/yaffs2/yaffs2/yaffs_attribs.c
@@ -0,0 +1,124 @@
+/*
+ * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
+ *
+ * Copyright (C) 2002-2011 Aleph One Ltd.
+ *   for Toby Churchill Ltd and Brightstar Engineering
+ *
+ * Created by Charles Manning <charles@aleph1.co.uk>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include "yaffs_guts.h"
+#include "yaffs_attribs.h"
+
+void yaffs_load_attribs(struct yaffs_obj *obj, struct yaffs_obj_hdr *oh)
+{
+	obj->yst_uid = oh->yst_uid;
+	obj->yst_gid = oh->yst_gid;
+	obj->yst_atime = oh->yst_atime;
+	obj->yst_mtime = oh->yst_mtime;
+	obj->yst_ctime = oh->yst_ctime;
+	obj->yst_rdev = oh->yst_rdev;
+}
+
+void yaffs_load_attribs_oh(struct yaffs_obj_hdr *oh, struct yaffs_obj *obj)
+{
+	oh->yst_uid = obj->yst_uid;
+	oh->yst_gid = obj->yst_gid;
+	oh->yst_atime = obj->yst_atime;
+	oh->yst_mtime = obj->yst_mtime;
+	oh->yst_ctime = obj->yst_ctime;
+	oh->yst_rdev = obj->yst_rdev;
+
+}
+
+void yaffs_load_current_time(struct yaffs_obj *obj, int do_a, int do_c)
+{
+	obj->yst_mtime = Y_CURRENT_TIME;
+	if (do_a)
+		obj->yst_atime = obj->yst_mtime;
+	if (do_c)
+		obj->yst_ctime = obj->yst_mtime;
+}
+
+void yaffs_attribs_init(struct yaffs_obj *obj, u32 gid, u32 uid, u32 rdev)
+{
+	yaffs_load_current_time(obj, 1, 1);
+	obj->yst_rdev = rdev;
+	obj->yst_uid = uid;
+	obj->yst_gid = gid;
+}
+
+static loff_t yaffs_get_file_size(struct yaffs_obj *obj)
+{
+	YCHAR *alias = NULL;
+	obj = yaffs_get_equivalent_obj(obj);
+
+	switch (obj->variant_type) {
+	case YAFFS_OBJECT_TYPE_FILE:
+		return obj->variant.file_variant.file_size;
+	case YAFFS_OBJECT_TYPE_SYMLINK:
+		alias = obj->variant.symlink_variant.alias;
+		if (!alias)
+			return 0;
+		return strnlen(alias, YAFFS_MAX_ALIAS_LENGTH);
+	default:
+		return 0;
+	}
+}
+
+int yaffs_set_attribs(struct yaffs_obj *obj, struct iattr *attr)
+{
+	unsigned int valid = attr->ia_valid;
+
+	if (valid & ATTR_MODE)
+		obj->yst_mode = attr->ia_mode;
+	if (valid & ATTR_UID)
+		obj->yst_uid = attr->ia_uid;
+	if (valid & ATTR_GID)
+		obj->yst_gid = attr->ia_gid;
+
+	if (valid & ATTR_ATIME)
+		obj->yst_atime = Y_TIME_CONVERT(attr->ia_atime);
+	if (valid & ATTR_CTIME)
+		obj->yst_ctime = Y_TIME_CONVERT(attr->ia_ctime);
+	if (valid & ATTR_MTIME)
+		obj->yst_mtime = Y_TIME_CONVERT(attr->ia_mtime);
+
+	if (valid & ATTR_SIZE)
+		yaffs_resize_file(obj, attr->ia_size);
+
+	yaffs_update_oh(obj, NULL, 1, 0, 0, NULL);
+
+	return YAFFS_OK;
+
+}
+
+int yaffs_get_attribs(struct yaffs_obj *obj, struct iattr *attr)
+{
+	unsigned int valid = 0;
+
+	attr->ia_mode = obj->yst_mode;
+	valid |= ATTR_MODE;
+	attr->ia_uid = obj->yst_uid;
+	valid |= ATTR_UID;
+	attr->ia_gid = obj->yst_gid;
+	valid |= ATTR_GID;
+
+	Y_TIME_CONVERT(attr->ia_atime) = obj->yst_atime;
+	valid |= ATTR_ATIME;
+	Y_TIME_CONVERT(attr->ia_ctime) = obj->yst_ctime;
+	valid |= ATTR_CTIME;
+	Y_TIME_CONVERT(attr->ia_mtime) = obj->yst_mtime;
+	valid |= ATTR_MTIME;
+
+	attr->ia_size = yaffs_get_file_size(obj);
+	valid |= ATTR_SIZE;
+
+	attr->ia_valid = valid;
+
+	return YAFFS_OK;
+}
diff --git a/linux-bsp/asm-study/yaffs2/yaffs2/yaffs_attribs.h b/linux-bsp/asm-study/yaffs2/yaffs2/yaffs_attribs.h
new file mode 100644
index 0000000..5b21b08
--- /dev/null
+++ b/linux-bsp/asm-study/yaffs2/yaffs2/yaffs_attribs.h
@@ -0,0 +1,28 @@
+/*
+ * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
+ *
+ * Copyright (C) 2002-2011 Aleph One Ltd.
+ *   for Toby Churchill Ltd and Brightstar Engineering
+ *
+ * Created by Charles Manning <charles@aleph1.co.uk>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 2.1 as
+ * published by the Free Software Foundation.
+ *
+ * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
+ */
+
+#ifndef __YAFFS_ATTRIBS_H__
+#define __YAFFS_ATTRIBS_H__
+
+#include "yaffs_guts.h"
+
+void yaffs_load_attribs(struct yaffs_obj *obj, struct yaffs_obj_hdr *oh);
+void yaffs_load_attribs_oh(struct yaffs_obj_hdr *oh, struct yaffs_obj *obj);
+void yaffs_attribs_init(struct yaffs_obj *obj, u32 gid, u32 uid, u32 rdev);
+void yaffs_load_current_time(struct yaffs_obj *obj, int do_a, int do_c);
+int yaffs_set_attribs(struct yaffs_obj *obj, struct iattr *attr);
+int yaffs_get_attribs(struct yaffs_obj *obj, struct iattr *attr);
+
+#endif
diff --git a/linux-bsp/asm-study/yaffs2/yaffs2/yaffs_bitmap.c b/linux-bsp/asm-study/yaffs2/yaffs2/yaffs_bitmap.c
new file mode 100644
index 0000000..4440e93
--- /dev/null
+++ b/linux-bsp/asm-study/yaffs2/yaffs2/yaffs_bitmap.c
@@ -0,0 +1,97 @@
+/*
+ * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
+ *
+ * Copyright (C) 2002-2011 Aleph One Ltd.
+ *   for Toby Churchill Ltd and Brightstar Engineering
+ *
+ * Created by Charles Manning <charles@aleph1.co.uk>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include "yaffs_bitmap.h"
+#include "yaffs_trace.h"
+/*
+ * Chunk bitmap manipulations
+ */
+
+static inline u8 *yaffs_block_bits(struct yaffs_dev *dev, int blk)
+{
+	if (blk < dev->internal_start_block || blk > dev->internal_end_block) {
+		yaffs_trace(YAFFS_TRACE_ERROR,
+			"BlockBits block %d is not valid",
+			blk);
+		BUG();
+	}
+	return dev->chunk_bits +
+	    (dev->chunk_bit_stride * (blk - dev->internal_start_block));
+}
+
+void yaffs_verify_chunk_bit_id(struct yaffs_dev *dev, int blk, int chunk)
+{
+	if (blk < dev->internal_start_block || blk > dev->internal_end_block ||
+	    chunk < 0 || chunk >= dev->param.chunks_per_block) {
+		yaffs_trace(YAFFS_TRACE_ERROR,
+			"Chunk Id (%d:%d) invalid",
+			blk, chunk);
+		BUG();
+	}
+}
+
+void yaffs_clear_chunk_bits(struct yaffs_dev *dev, int blk)
+{
+	u8 *blk_bits = yaffs_block_bits(dev, blk);
+
+	memset(blk_bits, 0, dev->chunk_bit_stride);
+}
+
+void yaffs_clear_chunk_bit(struct yaffs_dev *dev, int blk, int chunk)
+{
+	u8 *blk_bits = yaffs_block_bits(dev, blk);
+
+	yaffs_verify_chunk_bit_id(dev, blk, chunk);
+	blk_bits[chunk / 8] &= ~(1 << (chunk & 7));
+}
+
+void yaffs_set_chunk_bit(struct yaffs_dev *dev, int blk, int chunk)
+{
+	u8 *blk_bits = yaffs_block_bits(dev, blk);
+
+	yaffs_verify_chunk_bit_id(dev, blk, chunk);
+	blk_bits[chunk / 8] |= (1 << (chunk & 7));
+}
+
+int yaffs_check_chunk_bit(struct yaffs_dev *dev, int blk, int chunk)
+{
+	u8 *blk_bits = yaffs_block_bits(dev, blk);
+
+	yaffs_verify_chunk_bit_id(dev, blk, chunk);
+	return (blk_bits[chunk / 8] & (1 << (chunk & 7))) ? 1 : 0;
+}
+
+int yaffs_still_some_chunks(struct yaffs_dev *dev, int blk)
+{
+	u8 *blk_bits = yaffs_block_bits(dev, blk);
+	int i;
+
+	for (i = 0; i < dev->chunk_bit_stride; i++) {
+		if (*blk_bits)
+			return 1;
+		blk_bits++;
+	}
+	return 0;
+}
+
+int yaffs_count_chunk_bits(struct yaffs_dev *dev, int blk)
+{
+	u8 *blk_bits = yaffs_block_bits(dev, blk);
+	int i;
+	int n = 0;
+
+	for (i = 0; i < dev->chunk_bit_stride; i++, blk_bits++)
+		n += hweight8(*blk_bits);
+
+	return n;
+}
diff --git a/linux-bsp/asm-study/yaffs2/yaffs2/yaffs_bitmap.h b/linux-bsp/asm-study/yaffs2/yaffs2/yaffs_bitmap.h
new file mode 100644
index 0000000..e26b37d
--- /dev/null
+++ b/linux-bsp/asm-study/yaffs2/yaffs2/yaffs_bitmap.h
@@ -0,0 +1,33 @@
+/*
+ * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
+ *
+ * Copyright (C) 2002-2011 Aleph One Ltd.
+ *   for Toby Churchill Ltd and Brightstar Engineering
+ *
+ * Created by Charles Manning <charles@aleph1.co.uk>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 2.1 as
+ * published by the Free Software Foundation.
+ *
+ * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
+ */
+
+/*
+ * Chunk bitmap manipulations
+ */
+
+#ifndef __YAFFS_BITMAP_H__
+#define __YAFFS_BITMAP_H__
+
+#include "yaffs_guts.h"
+
+void yaffs_verify_chunk_bit_id(struct yaffs_dev *dev, int blk, int chunk);
+void yaffs_clear_chunk_bits(struct yaffs_dev *dev, int blk);
+void yaffs_clear_chunk_bit(struct yaffs_dev *dev, int blk, int chunk);
+void yaffs_set_chunk_bit(struct yaffs_dev *dev, int blk, int chunk);
+int yaffs_check_chunk_bit(struct yaffs_dev *dev, int blk, int chunk);
+int yaffs_still_some_chunks(struct yaffs_dev *dev, int blk);
+int yaffs_count_chunk_bits(struct yaffs_dev *dev, int blk);
+
+#endif
diff --git a/linux-bsp/asm-study/yaffs2/yaffs2/yaffs_checkptrw.c b/linux-bsp/asm-study/yaffs2/yaffs2/yaffs_checkptrw.c
new file mode 100644
index 0000000..8478eb8
--- /dev/null
+++ b/linux-bsp/asm-study/yaffs2/yaffs2/yaffs_checkptrw.c
@@ -0,0 +1,473 @@
+/*
+ * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
+ *
+ * Copyright (C) 2002-2011 Aleph One Ltd.
+ *   for Toby Churchill Ltd and Brightstar Engineering
+ *
+ * Created by Charles Manning <charles@aleph1.co.uk>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include "yaffs_checkptrw.h"
+#include "yaffs_getblockinfo.h"
+
+struct yaffs_checkpt_chunk_hdr {
+	int version;
+	int seq;
+	u32 sum;
+	u32 xor;
+} ;
+
+
+static int apply_chunk_offset(struct yaffs_dev *dev, int chunk)
+{
+	return chunk - dev->chunk_offset;
+}
+
+static int apply_block_offset(struct yaffs_dev *dev, int block)
+{
+	return block - dev->block_offset;
+}
+
+static void yaffs2_checkpt_init_chunk_hdr(struct yaffs_dev *dev)
+{
+	struct yaffs_checkpt_chunk_hdr hdr;
+
+	hdr.version = YAFFS_CHECKPOINT_VERSION;
+	hdr.seq = dev->checkpt_page_seq;
+	hdr.sum = dev->checkpt_sum;
+	hdr.xor = dev->checkpt_xor;
+
+	dev->checkpt_byte_offs = sizeof(hdr);
+
+	memcpy(dev->checkpt_buffer, &hdr, sizeof(hdr));
+}
+
+static int yaffs2_checkpt_check_chunk_hdr(struct yaffs_dev *dev)
+{
+	struct yaffs_checkpt_chunk_hdr hdr;
+
+	memcpy(&hdr, dev->checkpt_buffer, sizeof(hdr));
+
+	dev->checkpt_byte_offs = sizeof(hdr);
+
+	return hdr.version == YAFFS_CHECKPOINT_VERSION &&
+		hdr.seq == dev->checkpt_page_seq &&
+		hdr.sum == dev->checkpt_sum &&
+		hdr.xor == dev->checkpt_xor;
+}
+
+static int yaffs2_checkpt_space_ok(struct yaffs_dev *dev)
+{
+	int blocks_avail = dev->n_erased_blocks - dev->param.n_reserved_blocks;
+
+	yaffs_trace(YAFFS_TRACE_CHECKPOINT,
+		"checkpt blocks_avail = %d", blocks_avail);
+
+	return (blocks_avail <= 0) ? 0 : 1;
+}
+
+static int yaffs_checkpt_erase(struct yaffs_dev *dev)
+{
+	int i;
+
+	if (!dev->param.erase_fn)
+		return 0;
+	yaffs_trace(YAFFS_TRACE_CHECKPOINT,
+		"checking blocks %d to %d",
+		dev->internal_start_block, dev->internal_end_block);
+
+	for (i = dev->internal_start_block; i <= dev->internal_end_block; i++) {
+		struct yaffs_block_info *bi = yaffs_get_block_info(dev, i);
+		int offset_i = apply_block_offset(dev, i);
+		int result;
+
+		if (bi->block_state == YAFFS_BLOCK_STATE_CHECKPOINT) {
+			yaffs_trace(YAFFS_TRACE_CHECKPOINT,
+			"erasing checkpt block %d", i);
+
+			dev->n_erasures++;
+
+			result = dev->param.erase_fn(dev, offset_i);
+			if(result) {
+				bi->block_state = YAFFS_BLOCK_STATE_EMPTY;
+				dev->n_erased_blocks++;
+				dev->n_free_chunks +=
+				    dev->param.chunks_per_block;
+			} else {
+				dev->param.bad_block_fn(dev, offset_i);
+				bi->block_state = YAFFS_BLOCK_STATE_DEAD;
+			}
+		}
+	}
+
+	dev->blocks_in_checkpt = 0;
+
+	return 1;
+}
+
+static void yaffs2_checkpt_find_erased_block(struct yaffs_dev *dev)
+{
+	int i;
+	int blocks_avail = dev->n_erased_blocks - dev->param.n_reserved_blocks;
+
+	yaffs_trace(YAFFS_TRACE_CHECKPOINT,
+		"allocating checkpt block: erased %d reserved %d avail %d next %d ",
+		dev->n_erased_blocks, dev->param.n_reserved_blocks,
+		blocks_avail, dev->checkpt_next_block);
+
+	if (dev->checkpt_next_block >= 0 &&
+	    dev->checkpt_next_block <= dev->internal_end_block &&
+	    blocks_avail > 0) {
+
+		for (i = dev->checkpt_next_block; i <= dev->internal_end_block;
+		     i++) {
+			struct yaffs_block_info *bi;
+
+			bi = yaffs_get_block_info(dev, i);
+			if (bi->block_state == YAFFS_BLOCK_STATE_EMPTY) {
+				dev->checkpt_next_block = i + 1;
+				dev->checkpt_cur_block = i;
+				yaffs_trace(YAFFS_TRACE_CHECKPOINT,
+					"allocating checkpt block %d", i);
+				return;
+			}
+		}
+	}
+	yaffs_trace(YAFFS_TRACE_CHECKPOINT, "out of checkpt blocks");
+
+	dev->checkpt_next_block = -1;
+	dev->checkpt_cur_block = -1;
+}
+
+static void yaffs2_checkpt_find_block(struct yaffs_dev *dev)
+{
+	int i;
+	struct yaffs_ext_tags tags;
+
+	yaffs_trace(YAFFS_TRACE_CHECKPOINT,
+		"find next checkpt block: start:  blocks %d next %d",
+		dev->blocks_in_checkpt, dev->checkpt_next_block);
+
+	if (dev->blocks_in_checkpt < dev->checkpt_max_blocks)
+		for (i = dev->checkpt_next_block; i <= dev->internal_end_block;
+		     i++) {
+			int chunk = i * dev->param.chunks_per_block;
+			enum yaffs_block_state state;
+			u32 seq;
+
+			dev->param.read_chunk_tags_fn(dev,
+					apply_chunk_offset(dev, chunk),
+					NULL, &tags);
+			yaffs_trace(YAFFS_TRACE_CHECKPOINT,
+				"find next checkpt block: search: block %d state %d oid %d seq %d eccr %d",
+				i, (int) state,
+				tags.obj_id, tags.seq_number,
+				tags.ecc_result);
+
+			if (tags.seq_number != YAFFS_SEQUENCE_CHECKPOINT_DATA)
+				continue;
+
+			dev->param.query_block_fn(dev,
+						apply_block_offset(dev, i),
+						&state, &seq);
+			if (state == YAFFS_BLOCK_STATE_DEAD)
+				continue;
+
+			/* Right kind of block */
+			dev->checkpt_next_block = tags.obj_id;
+			dev->checkpt_cur_block = i;
+			dev->checkpt_block_list[dev->blocks_in_checkpt] = i;
+			dev->blocks_in_checkpt++;
+			yaffs_trace(YAFFS_TRACE_CHECKPOINT,
+				"found checkpt block %d", i);
+			return;
+		}
+
+	yaffs_trace(YAFFS_TRACE_CHECKPOINT, "found no more checkpt blocks");
+
+	dev->checkpt_next_block = -1;
+	dev->checkpt_cur_block = -1;
+}
+
+int yaffs2_checkpt_open(struct yaffs_dev *dev, int writing)
+{
+	int i;
+
+	dev->checkpt_open_write = writing;
+
+	/* Got the functions we need? */
+	if (!dev->param.write_chunk_tags_fn ||
+	    !dev->param.read_chunk_tags_fn ||
+	    !dev->param.erase_fn || !dev->param.bad_block_fn)
+		return 0;
+
+	if (writing && !yaffs2_checkpt_space_ok(dev))
+		return 0;
+
+	if (!dev->checkpt_buffer)
+		dev->checkpt_buffer =
+		    kmalloc(dev->param.total_bytes_per_chunk, GFP_NOFS);
+	if (!dev->checkpt_buffer)
+		return 0;
+
+	dev->checkpt_page_seq = 0;
+	dev->checkpt_byte_count = 0;
+	dev->checkpt_sum = 0;
+	dev->checkpt_xor = 0;
+	dev->checkpt_cur_block = -1;
+	dev->checkpt_cur_chunk = -1;
+	dev->checkpt_next_block = dev->internal_start_block;
+
+	if (writing) {
+		memset(dev->checkpt_buffer, 0, dev->data_bytes_per_chunk);
+		yaffs2_checkpt_init_chunk_hdr(dev);
+		return yaffs_checkpt_erase(dev);
+	}
+
+	/* Opening for a read */
+	/* Set to a value that will kick off a read */
+	dev->checkpt_byte_offs = dev->data_bytes_per_chunk;
+	/* A checkpoint block list of 1 checkpoint block per 16 block is
+	 * (hopefully) going to be way more than we need */
+	dev->blocks_in_checkpt = 0;
+	dev->checkpt_max_blocks =
+	    (dev->internal_end_block - dev->internal_start_block) / 16 + 2;
+	dev->checkpt_block_list =
+	    kmalloc(sizeof(int) * dev->checkpt_max_blocks, GFP_NOFS);
+
+	if (!dev->checkpt_block_list)
+		return 0;
+
+	for (i = 0; i < dev->checkpt_max_blocks; i++)
+		dev->checkpt_block_list[i] = -1;
+
+	return 1;
+}
+
+int yaffs2_get_checkpt_sum(struct yaffs_dev *dev, u32 * sum)
+{
+	u32 composite_sum;
+
+	composite_sum = (dev->checkpt_sum << 8) | (dev->checkpt_xor & 0xff);
+	*sum = composite_sum;
+	return 1;
+}
+
+static int yaffs2_checkpt_flush_buffer(struct yaffs_dev *dev)
+{
+	int chunk;
+	int offset_chunk;
+	struct yaffs_ext_tags tags;
+
+	if (dev->checkpt_cur_block < 0) {
+		yaffs2_checkpt_find_erased_block(dev);
+		dev->checkpt_cur_chunk = 0;
+	}
+
+	if (dev->checkpt_cur_block < 0)
+		return 0;
+
+	tags.is_deleted = 0;
+	tags.obj_id = dev->checkpt_next_block;	/* Hint to next place to look */
+	tags.chunk_id = dev->checkpt_page_seq + 1;
+	tags.seq_number = YAFFS_SEQUENCE_CHECKPOINT_DATA;
+	tags.n_bytes = dev->data_bytes_per_chunk;
+	if (dev->checkpt_cur_chunk == 0) {
+		/* First chunk we write for the block? Set block state to
+		   checkpoint */
+		struct yaffs_block_info *bi =
+		    yaffs_get_block_info(dev, dev->checkpt_cur_block);
+		bi->block_state = YAFFS_BLOCK_STATE_CHECKPOINT;
+		dev->blocks_in_checkpt++;
+	}
+
+	chunk =
+	    dev->checkpt_cur_block * dev->param.chunks_per_block +
+	    dev->checkpt_cur_chunk;
+
+	yaffs_trace(YAFFS_TRACE_CHECKPOINT,
+		"checkpoint wite buffer nand %d(%d:%d) objid %d chId %d",
+		chunk, dev->checkpt_cur_block, dev->checkpt_cur_chunk,
+		tags.obj_id, tags.chunk_id);
+
+	offset_chunk = apply_chunk_offset(dev, chunk);
+
+	dev->n_page_writes++;
+
+	dev->param.write_chunk_tags_fn(dev, offset_chunk,
+				       dev->checkpt_buffer, &tags);
+	dev->checkpt_page_seq++;
+	dev->checkpt_cur_chunk++;
+	if (dev->checkpt_cur_chunk >= dev->param.chunks_per_block) {
+		dev->checkpt_cur_chunk = 0;
+		dev->checkpt_cur_block = -1;
+	}
+	memset(dev->checkpt_buffer, 0, dev->data_bytes_per_chunk);
+
+	yaffs2_checkpt_init_chunk_hdr(dev);
+
+
+	return 1;
+}
+
+int yaffs2_checkpt_wr(struct yaffs_dev *dev, const void *data, int n_bytes)
+{
+	int i = 0;
+	int ok = 1;
+	u8 *data_bytes = (u8 *) data;
+
+	if (!dev->checkpt_buffer)
+		return 0;
+
+	if (!dev->checkpt_open_write)
+		return -1;
+
+	while (i < n_bytes && ok) {
+		dev->checkpt_buffer[dev->checkpt_byte_offs] = *data_bytes;
+		dev->checkpt_sum += *data_bytes;
+		dev->checkpt_xor ^= *data_bytes;
+
+		dev->checkpt_byte_offs++;
+		i++;
+		data_bytes++;
+		dev->checkpt_byte_count++;
+
+		if (dev->checkpt_byte_offs < 0 ||
+		    dev->checkpt_byte_offs >= dev->data_bytes_per_chunk)
+			ok = yaffs2_checkpt_flush_buffer(dev);
+	}
+
+	return i;
+}
+
+int yaffs2_checkpt_rd(struct yaffs_dev *dev, void *data, int n_bytes)
+{
+	int i = 0;
+	int ok = 1;
+	struct yaffs_ext_tags tags;
+	int chunk;
+	int offset_chunk;
+	u8 *data_bytes = (u8 *) data;
+
+	if (!dev->checkpt_buffer)
+		return 0;
+
+	if (dev->checkpt_open_write)
+		return -1;
+
+	while (i < n_bytes && ok) {
+
+		if (dev->checkpt_byte_offs < 0 ||
+		    dev->checkpt_byte_offs >= dev->data_bytes_per_chunk) {
+
+			if (dev->checkpt_cur_block < 0) {
+				yaffs2_checkpt_find_block(dev);
+				dev->checkpt_cur_chunk = 0;
+			}
+
+			if (dev->checkpt_cur_block < 0) {
+				ok = 0;
+				break;
+			}
+
+			chunk = dev->checkpt_cur_block *
+			    dev->param.chunks_per_block +
+			    dev->checkpt_cur_chunk;
+
+			offset_chunk = apply_chunk_offset(dev, chunk);
+			dev->n_page_reads++;
+
+			/* read in the next chunk */
+			dev->param.read_chunk_tags_fn(dev,
+						offset_chunk,
+						dev->checkpt_buffer,
+						&tags);
+
+			if (tags.chunk_id != (dev->checkpt_page_seq + 1) ||
+			    tags.ecc_result > YAFFS_ECC_RESULT_FIXED ||
+			    tags.seq_number != YAFFS_SEQUENCE_CHECKPOINT_DATA) {
+				ok = 0;
+				break;
+			}
+			if(!yaffs2_checkpt_check_chunk_hdr(dev)) {
+				ok = 0;
+				break;
+			}
+
+			dev->checkpt_page_seq++;
+			dev->checkpt_cur_chunk++;
+
+			if (dev->checkpt_cur_chunk >=
+					dev->param.chunks_per_block)
+				dev->checkpt_cur_block = -1;
+
+		}
+
+		*data_bytes = dev->checkpt_buffer[dev->checkpt_byte_offs];
+		dev->checkpt_sum += *data_bytes;
+		dev->checkpt_xor ^= *data_bytes;
+		dev->checkpt_byte_offs++;
+		i++;
+		data_bytes++;
+		dev->checkpt_byte_count++;
+	}
+
+	return i;
+}
+
+int yaffs_checkpt_close(struct yaffs_dev *dev)
+{
+	int i;
+
+	if (dev->checkpt_open_write) {
+		if (dev->checkpt_byte_offs !=
+			sizeof(sizeof(struct yaffs_checkpt_chunk_hdr)))
+			yaffs2_checkpt_flush_buffer(dev);
+	} else if (dev->checkpt_block_list) {
+		for (i = 0;
+		     i < dev->blocks_in_checkpt &&
+		     dev->checkpt_block_list[i] >= 0; i++) {
+			int blk = dev->checkpt_block_list[i];
+			struct yaffs_block_info *bi = NULL;
+
+			if (dev->internal_start_block <= blk &&
+			    blk <= dev->internal_end_block)
+				bi = yaffs_get_block_info(dev, blk);
+			if (bi && bi->block_state == YAFFS_BLOCK_STATE_EMPTY)
+				bi->block_state = YAFFS_BLOCK_STATE_CHECKPOINT;
+		}
+		kfree(dev->checkpt_block_list);
+		dev->checkpt_block_list = NULL;
+	}
+
+	dev->n_free_chunks -=
+		dev->blocks_in_checkpt * dev->param.chunks_per_block;
+	dev->n_erased_blocks -= dev->blocks_in_checkpt;
+
+	yaffs_trace(YAFFS_TRACE_CHECKPOINT, "checkpoint byte count %d",
+		dev->checkpt_byte_count);
+
+	if (dev->checkpt_buffer) {
+		/* free the buffer */
+		kfree(dev->checkpt_buffer);
+		dev->checkpt_buffer = NULL;
+		return 1;
+	} else {
+		return 0;
+	}
+}
+
+int yaffs2_checkpt_invalidate_stream(struct yaffs_dev *dev)
+{
+	/* Erase the checkpoint data */
+
+	yaffs_trace(YAFFS_TRACE_CHECKPOINT,
+		"checkpoint invalidate of %d blocks",
+		dev->blocks_in_checkpt);
+
+	return yaffs_checkpt_erase(dev);
+}
diff --git a/linux-bsp/asm-study/yaffs2/yaffs2/yaffs_checkptrw.h b/linux-bsp/asm-study/yaffs2/yaffs2/yaffs_checkptrw.h
new file mode 100644
index 0000000..cdbaba7
--- /dev/null
+++ b/linux-bsp/asm-study/yaffs2/yaffs2/yaffs_checkptrw.h
@@ -0,0 +1,33 @@
+/*
+ * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
+ *
+ * Copyright (C) 2002-2011 Aleph One Ltd.
+ *   for Toby Churchill Ltd and Brightstar Engineering
+ *
+ * Created by Charles Manning <charles@aleph1.co.uk>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 2.1 as
+ * published by the Free Software Foundation.
+ *
+ * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
+ */
+
+#ifndef __YAFFS_CHECKPTRW_H__
+#define __YAFFS_CHECKPTRW_H__
+
+#include "yaffs_guts.h"
+
+int yaffs2_checkpt_open(struct yaffs_dev *dev, int writing);
+
+int yaffs2_checkpt_wr(struct yaffs_dev *dev, const void *data, int n_bytes);
+
+int yaffs2_checkpt_rd(struct yaffs_dev *dev, void *data, int n_bytes);
+
+int yaffs2_get_checkpt_sum(struct yaffs_dev *dev, u32 * sum);
+
+int yaffs_checkpt_close(struct yaffs_dev *dev);
+
+int yaffs2_checkpt_invalidate_stream(struct yaffs_dev *dev);
+
+#endif
diff --git a/linux-bsp/asm-study/yaffs2/yaffs2/yaffs_ecc.c b/linux-bsp/asm-study/yaffs2/yaffs2/yaffs_ecc.c
new file mode 100644
index 0000000..9294107
--- /dev/null
+++ b/linux-bsp/asm-study/yaffs2/yaffs2/yaffs_ecc.c
@@ -0,0 +1,281 @@
+/*
+ * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
+ *
+ * Copyright (C) 2002-2011 Aleph One Ltd.
+ *   for Toby Churchill Ltd and Brightstar Engineering
+ *
+ * Created by Charles Manning <charles@aleph1.co.uk>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+/*
+ * This code implements the ECC algorithm used in SmartMedia.
+ *
+ * The ECC comprises 22 bits of parity information and is stuffed into 3 bytes.
+ * The two unused bit are set to 1.
+ * The ECC can correct single bit errors in a 256-byte page of data. Thus, two
+ * such ECC blocks are used on a 512-byte NAND page.
+ *
+ */
+
+#include "yportenv.h"
+
+#include "yaffs_ecc.h"
+
+/* Table generated by gen-ecc.c
+ * Using a table means we do not have to calculate p1..p4 and p1'..p4'
+ * for each byte of data. These are instead provided in a table in bits7..2.
+ * Bit 0 of each entry indicates whether the entry has an odd or even parity,
+ * and therefore this bytes influence on the line parity.
+ */
+
+static const unsigned char column_parity_table[] = {
+	0x00, 0x55, 0x59, 0x0c, 0x65, 0x30, 0x3c, 0x69,
+	0x69, 0x3c, 0x30, 0x65, 0x0c, 0x59, 0x55, 0x00,
+	0x95, 0xc0, 0xcc, 0x99, 0xf0, 0xa5, 0xa9, 0xfc,
+	0xfc, 0xa9, 0xa5, 0xf0, 0x99, 0xcc, 0xc0, 0x95,
+	0x99, 0xcc, 0xc0, 0x95, 0xfc, 0xa9, 0xa5, 0xf0,
+	0xf0, 0xa5, 0xa9, 0xfc, 0x95, 0xc0, 0xcc, 0x99,
+	0x0c, 0x59, 0x55, 0x00, 0x69, 0x3c, 0x30, 0x65,
+	0x65, 0x30, 0x3c, 0x69, 0x00, 0x55, 0x59, 0x0c,
+	0xa5, 0xf0, 0xfc, 0xa9, 0xc0, 0x95, 0x99, 0xcc,
+	0xcc, 0x99, 0x95, 0xc0, 0xa9, 0xfc, 0xf0, 0xa5,
+	0x30, 0x65, 0x69, 0x3c, 0x55, 0x00, 0x0c, 0x59,
+	0x59, 0x0c, 0x00, 0x55, 0x3c, 0x69, 0x65, 0x30,
+	0x3c, 0x69, 0x65, 0x30, 0x59, 0x0c, 0x00, 0x55,
+	0x55, 0x00, 0x0c, 0x59, 0x30, 0x65, 0x69, 0x3c,
+	0xa9, 0xfc, 0xf0, 0xa5, 0xcc, 0x99, 0x95, 0xc0,
+	0xc0, 0x95, 0x99, 0xcc, 0xa5, 0xf0, 0xfc, 0xa9,
+	0xa9, 0xfc, 0xf0, 0xa5, 0xcc, 0x99, 0x95, 0xc0,
+	0xc0, 0x95, 0x99, 0xcc, 0xa5, 0xf0, 0xfc, 0xa9,
+	0x3c, 0x69, 0x65, 0x30, 0x59, 0x0c, 0x00, 0x55,
+	0x55, 0x00, 0x0c, 0x59, 0x30, 0x65, 0x69, 0x3c,
+	0x30, 0x65, 0x69, 0x3c, 0x55, 0x00, 0x0c, 0x59,
+	0x59, 0x0c, 0x00, 0x55, 0x3c, 0x69, 0x65, 0x30,
+	0xa5, 0xf0, 0xfc, 0xa9, 0xc0, 0x95, 0x99, 0xcc,
+	0xcc, 0x99, 0x95, 0xc0, 0xa9, 0xfc, 0xf0, 0xa5,
+	0x0c, 0x59, 0x55, 0x00, 0x69, 0x3c, 0x30, 0x65,
+	0x65, 0x30, 0x3c, 0x69, 0x00, 0x55, 0x59, 0x0c,
+	0x99, 0xcc, 0xc0, 0x95, 0xfc, 0xa9, 0xa5, 0xf0,
+	0xf0, 0xa5, 0xa9, 0xfc, 0x95, 0xc0, 0xcc, 0x99,
+	0x95, 0xc0, 0xcc, 0x99, 0xf0, 0xa5, 0xa9, 0xfc,
+	0xfc, 0xa9, 0xa5, 0xf0, 0x99, 0xcc, 0xc0, 0x95,
+	0x00, 0x55, 0x59, 0x0c, 0x65, 0x30, 0x3c, 0x69,
+	0x69, 0x3c, 0x30, 0x65, 0x0c, 0x59, 0x55, 0x00,
+};
+
+
+/* Calculate the ECC for a 256-byte block of data */
+void yaffs_ecc_calc(const unsigned char *data, unsigned char *ecc)
+{
+	unsigned int i;
+	unsigned char col_parity = 0;
+	unsigned char line_parity = 0;
+	unsigned char line_parity_prime = 0;
+	unsigned char t;
+	unsigned char b;
+
+	for (i = 0; i < 256; i++) {
+		b = column_parity_table[*data++];
+		col_parity ^= b;
+
+		if (b & 0x01) {	/* odd number of bits in the byte */
+			line_parity ^= i;
+			line_parity_prime ^= ~i;
+		}
+	}
+
+	ecc[2] = (~col_parity) | 0x03;
+
+	t = 0;
+	if (line_parity & 0x80)
+		t |= 0x80;
+	if (line_parity_prime & 0x80)
+		t |= 0x40;
+	if (line_parity & 0x40)
+		t |= 0x20;
+	if (line_parity_prime & 0x40)
+		t |= 0x10;
+	if (line_parity & 0x20)
+		t |= 0x08;
+	if (line_parity_prime & 0x20)
+		t |= 0x04;
+	if (line_parity & 0x10)
+		t |= 0x02;
+	if (line_parity_prime & 0x10)
+		t |= 0x01;
+	ecc[1] = ~t;
+
+	t = 0;
+	if (line_parity & 0x08)
+		t |= 0x80;
+	if (line_parity_prime & 0x08)
+		t |= 0x40;
+	if (line_parity & 0x04)
+		t |= 0x20;
+	if (line_parity_prime & 0x04)
+		t |= 0x10;
+	if (line_parity & 0x02)
+		t |= 0x08;
+	if (line_parity_prime & 0x02)
+		t |= 0x04;
+	if (line_parity & 0x01)
+		t |= 0x02;
+	if (line_parity_prime & 0x01)
+		t |= 0x01;
+	ecc[0] = ~t;
+
+}
+
+/* Correct the ECC on a 256 byte block of data */
+
+int yaffs_ecc_correct(unsigned char *data, unsigned char *read_ecc,
+		      const unsigned char *test_ecc)
+{
+	unsigned char d0, d1, d2;	/* deltas */
+
+	d0 = read_ecc[0] ^ test_ecc[0];
+	d1 = read_ecc[1] ^ test_ecc[1];
+	d2 = read_ecc[2] ^ test_ecc[2];
+
+	if ((d0 | d1 | d2) == 0)
+		return 0;	/* no error */
+
+	if (((d0 ^ (d0 >> 1)) & 0x55) == 0x55 &&
+	    ((d1 ^ (d1 >> 1)) & 0x55) == 0x55 &&
+	    ((d2 ^ (d2 >> 1)) & 0x54) == 0x54) {
+		/* Single bit (recoverable) error in data */
+
+		unsigned byte;
+		unsigned bit;
+
+		bit = byte = 0;
+
+		if (d1 & 0x80)
+			byte |= 0x80;
+		if (d1 & 0x20)
+			byte |= 0x40;
+		if (d1 & 0x08)
+			byte |= 0x20;
+		if (d1 & 0x02)
+			byte |= 0x10;
+		if (d0 & 0x80)
+			byte |= 0x08;
+		if (d0 & 0x20)
+			byte |= 0x04;
+		if (d0 & 0x08)
+			byte |= 0x02;
+		if (d0 & 0x02)
+			byte |= 0x01;
+
+		if (d2 & 0x80)
+			bit |= 0x04;
+		if (d2 & 0x20)
+			bit |= 0x02;
+		if (d2 & 0x08)
+			bit |= 0x01;
+
+		data[byte] ^= (1 << bit);
+
+		return 1;	/* Corrected the error */
+	}
+
+	if ((hweight8(d0) + hweight8(d1) + hweight8(d2)) == 1) {
+		/* Reccoverable error in ecc */
+
+		read_ecc[0] = test_ecc[0];
+		read_ecc[1] = test_ecc[1];
+		read_ecc[2] = test_ecc[2];
+
+		return 1;	/* Corrected the error */
+	}
+
+	/* Unrecoverable error */
+
+	return -1;
+
+}
+
+/*
+ * ECCxxxOther does ECC calcs on arbitrary n bytes of data
+ */
+void yaffs_ecc_calc_other(const unsigned char *data, unsigned n_bytes,
+			  struct yaffs_ecc_other *ecc_other)
+{
+	unsigned int i;
+	unsigned char col_parity = 0;
+	unsigned line_parity = 0;
+	unsigned line_parity_prime = 0;
+	unsigned char b;
+
+	for (i = 0; i < n_bytes; i++) {
+		b = column_parity_table[*data++];
+		col_parity ^= b;
+
+		if (b & 0x01) {
+			/* odd number of bits in the byte */
+			line_parity ^= i;
+			line_parity_prime ^= ~i;
+		}
+
+	}
+
+	ecc_other->col_parity = (col_parity >> 2) & 0x3f;
+	ecc_other->line_parity = line_parity;
+	ecc_other->line_parity_prime = line_parity_prime;
+}
+
+int yaffs_ecc_correct_other(unsigned char *data, unsigned n_bytes,
+			    struct yaffs_ecc_other *read_ecc,
+			    const struct yaffs_ecc_other *test_ecc)
+{
+	unsigned char delta_col;	/* column parity delta */
+	unsigned delta_line;	/* line parity delta */
+	unsigned delta_line_prime;	/* line parity delta */
+	unsigned bit;
+
+	delta_col = read_ecc->col_parity ^ test_ecc->col_parity;
+	delta_line = read_ecc->line_parity ^ test_ecc->line_parity;
+	delta_line_prime =
+	    read_ecc->line_parity_prime ^ test_ecc->line_parity_prime;
+
+	if ((delta_col | delta_line | delta_line_prime) == 0)
+		return 0;	/* no error */
+
+	if (delta_line == ~delta_line_prime &&
+	    (((delta_col ^ (delta_col >> 1)) & 0x15) == 0x15)) {
+		/* Single bit (recoverable) error in data */
+
+		bit = 0;
+
+		if (delta_col & 0x20)
+			bit |= 0x04;
+		if (delta_col & 0x08)
+			bit |= 0x02;
+		if (delta_col & 0x02)
+			bit |= 0x01;
+
+		if (delta_line >= n_bytes)
+			return -1;
+
+		data[delta_line] ^= (1 << bit);
+
+		return 1;	/* corrected */
+	}
+
+	if ((hweight32(delta_line) +
+	     hweight32(delta_line_prime) +
+	     hweight8(delta_col)) == 1) {
+		/* Reccoverable error in ecc */
+
+		*read_ecc = *test_ecc;
+		return 1;	/* corrected */
+	}
+
+	/* Unrecoverable error */
+
+	return -1;
+}
diff --git a/linux-bsp/asm-study/yaffs2/yaffs2/yaffs_ecc.h b/linux-bsp/asm-study/yaffs2/yaffs2/yaffs_ecc.h
new file mode 100644
index 0000000..17d47bd
--- /dev/null
+++ b/linux-bsp/asm-study/yaffs2/yaffs2/yaffs_ecc.h
@@ -0,0 +1,44 @@
+/*
+ * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
+ *
+ * Copyright (C) 2002-2011 Aleph One Ltd.
+ *   for Toby Churchill Ltd and Brightstar Engineering
+ *
+ * Created by Charles Manning <charles@aleph1.co.uk>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 2.1 as
+ * published by the Free Software Foundation.
+ *
+ * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
+ */
+
+/*
+ * This code implements the ECC algorithm used in SmartMedia.
+ *
+ * The ECC comprises 22 bits of parity information and is stuffed into 3 bytes.
+ * The two unused bit are set to 1.
+ * The ECC can correct single bit errors in a 256-byte page of data.
+ * Thus, two such ECC blocks are used on a 512-byte NAND page.
+ *
+ */
+
+#ifndef __YAFFS_ECC_H__
+#define __YAFFS_ECC_H__
+
+struct yaffs_ecc_other {
+	unsigned char col_parity;
+	unsigned line_parity;
+	unsigned line_parity_prime;
+};
+
+void yaffs_ecc_calc(const unsigned char *data, unsigned char *ecc);
+int yaffs_ecc_correct(unsigned char *data, unsigned char *read_ecc,
+		      const unsigned char *test_ecc);
+
+void yaffs_ecc_calc_other(const unsigned char *data, unsigned n_bytes,
+			  struct yaffs_ecc_other *ecc);
+int yaffs_ecc_correct_other(unsigned char *data, unsigned n_bytes,
+			    struct yaffs_ecc_other *read_ecc,
+			    const struct yaffs_ecc_other *test_ecc);
+#endif
diff --git a/linux-bsp/asm-study/yaffs2/yaffs2/yaffs_error.c b/linux-bsp/asm-study/yaffs2/yaffs2/yaffs_error.c
new file mode 100644
index 0000000..11b75f7
--- /dev/null
+++ b/linux-bsp/asm-study/yaffs2/yaffs2/yaffs_error.c
@@ -0,0 +1,58 @@
+/*
+ * YAFFS: Yet another FFS. A NAND-flash specific file system.
+ *
+ * Copyright (C) 2002-2011 Aleph One Ltd.
+ *   for Toby Churchill Ltd and Brightstar Engineering
+ *
+ * Created by Timothy Manning <timothy@yaffs.net>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include "yaffsfs.h"
+
+struct error_entry {
+	int code;
+	const char *text;
+};
+
+static const struct error_entry error_list[] = {
+	{ ENOMEM , "ENOMEM" },
+	{ EBUSY , "EBUSY"},
+	{ ENODEV , "ENODEV"},
+	{ EINVAL , "EINVAL"},
+	{ EBADF , "EBADF"},
+	{ EACCES , "EACCES"},
+	{ EXDEV , "EXDEV" },
+	{ ENOENT , "ENOENT"},
+	{ ENOSPC , "ENOSPC"},
+	{ ERANGE , "ERANGE"},
+	{ ENODATA, "ENODATA"},
+	{ ENOTEMPTY, "ENOTEMPTY"},
+	{ ENAMETOOLONG, "ENAMETOOLONG"},
+	{ ENOMEM , "ENOMEM"},
+	{ EEXIST , "EEXIST"},
+	{ ENOTDIR , "ENOTDIR"},
+	{ EISDIR , "EISDIR"},
+	{ ENFILE, "ENFILE"},
+	{ EROFS, "EROFS"},
+	{ EFAULT, "EFAULT"},
+	{ 0, NULL }
+};
+
+const char *yaffs_error_to_str(int err)
+{
+	const struct error_entry *e = error_list;
+
+	if (err < 0)
+		err = -err;
+
+	while (e->code && e->text) {
+		if (err == e->code)
+			return e->text;
+		e++;
+	}
+	return "Unknown error code";
+}
diff --git a/linux-bsp/asm-study/yaffs2/yaffs2/yaffs_flashif.h b/linux-bsp/asm-study/yaffs2/yaffs2/yaffs_flashif.h
new file mode 100644
index 0000000..e6e8979
--- /dev/null
+++ b/linux-bsp/asm-study/yaffs2/yaffs2/yaffs_flashif.h
@@ -0,0 +1,35 @@
+/*
+ * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
+ *
+ * Copyright (C) 2002-2011 Aleph One Ltd.
+ *   for Toby Churchill Ltd and Brightstar Engineering
+ *
+ * Created by Charles Manning <charles@aleph1.co.uk>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 2.1 as
+ * published by the Free Software Foundation.
+ *
+ * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
+ */
+
+#ifndef __YAFFS_FLASH_H__
+#define __YAFFS_FLASH_H__
+
+
+#include "yaffs_guts.h"
+int yflash_EraseBlockInNAND(struct yaffs_dev *dev, int blockNumber);
+int yflash_WriteChunkToNAND(struct yaffs_dev *dev, int nand_chunk,
+			const u8 *data, const struct yaffs_spare *spare);
+int yflash_WriteChunkWithTagsToNAND(struct yaffs_dev *dev, int nand_chunk,
+			const u8 *data, const struct yaffs_ext_tags *tags);
+int yflash_ReadChunkFromNAND(struct yaffs_dev *dev, int nand_chunk,
+			u8 *data, struct yaffs_spare *spare);
+int yflash_ReadChunkWithTagsFromNAND(struct yaffs_dev *dev, int nand_chunk,
+			u8 *data, struct yaffs_ext_tags *tags);
+int yflash_InitialiseNAND(struct yaffs_dev *dev);
+int yflash_MarkNANDBlockBad(struct yaffs_dev *dev, int block_no);
+int yflash_QueryNANDBlock(struct yaffs_dev *dev, int block_no,
+			enum yaffs_block_state *state, u32 *seq_number);
+
+#endif
diff --git a/linux-bsp/asm-study/yaffs2/yaffs2/yaffs_flashif2.h b/linux-bsp/asm-study/yaffs2/yaffs2/yaffs_flashif2.h
new file mode 100644
index 0000000..cfdbde9
--- /dev/null
+++ b/linux-bsp/asm-study/yaffs2/yaffs2/yaffs_flashif2.h
@@ -0,0 +1,35 @@
+/*
+ * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
+ *
+ * Copyright (C) 2002-2011 Aleph One Ltd.
+ *   for Toby Churchill Ltd and Brightstar Engineering
+ *
+ * Created by Charles Manning <charles@aleph1.co.uk>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 2.1 as
+ * published by the Free Software Foundation.
+ *
+ * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
+ */
+
+#ifndef __YAFFS_FLASH2_H__
+#define __YAFFS_FLASH2_H__
+
+
+#include "yaffs_guts.h"
+int yflash2_EraseBlockInNAND(struct yaffs_dev *dev, int blockNumber);
+int yflash2_WriteChunkToNAND(struct yaffs_dev *dev, int nand_chunk,
+			const u8 *data, const struct yaffs_spare *spare);
+int yflash2_WriteChunkWithTagsToNAND(struct yaffs_dev *dev, int nand_chunk,
+			const u8 *data, const struct yaffs_ext_tags *tags);
+int yflash2_ReadChunkFromNAND(struct yaffs_dev *dev, int nand_chunk,
+			u8 *data, struct yaffs_spare *spare);
+int yflash2_ReadChunkWithTagsFromNAND(struct yaffs_dev *dev, int nand_chunk,
+			u8 *data, struct yaffs_ext_tags *tags);
+int yflash2_InitialiseNAND(struct yaffs_dev *dev);
+int yflash2_MarkNANDBlockBad(struct yaffs_dev *dev, int block_no);
+int yflash2_QueryNANDBlock(struct yaffs_dev *dev, int block_no,
+			enum yaffs_block_state *state, u32 *seq_number);
+
+#endif
diff --git a/linux-bsp/asm-study/yaffs2/yaffs2/yaffs_getblockinfo.h b/linux-bsp/asm-study/yaffs2/yaffs2/yaffs_getblockinfo.h
new file mode 100644
index 0000000..8fd0802
--- /dev/null
+++ b/linux-bsp/asm-study/yaffs2/yaffs2/yaffs_getblockinfo.h
@@ -0,0 +1,35 @@
+/*
+ * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
+ *
+ * Copyright (C) 2002-2011 Aleph One Ltd.
+ *   for Toby Churchill Ltd and Brightstar Engineering
+ *
+ * Created by Charles Manning <charles@aleph1.co.uk>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 2.1 as
+ * published by the Free Software Foundation.
+ *
+ * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
+ */
+
+#ifndef __YAFFS_GETBLOCKINFO_H__
+#define __YAFFS_GETBLOCKINFO_H__
+
+#include "yaffs_guts.h"
+#include "yaffs_trace.h"
+
+/* Function to manipulate block info */
+static inline struct yaffs_block_info *yaffs_get_block_info(struct yaffs_dev
+							      *dev, int blk)
+{
+	if (blk < dev->internal_start_block || blk > dev->internal_end_block) {
+		yaffs_trace(YAFFS_TRACE_ERROR,
+			"**>> yaffs: get_block_info block %d is not valid",
+			blk);
+		BUG();
+	}
+	return &dev->block_info[blk - dev->internal_start_block];
+}
+
+#endif
diff --git a/linux-bsp/asm-study/yaffs2/yaffs2/yaffs_guts.c b/linux-bsp/asm-study/yaffs2/yaffs2/yaffs_guts.c
new file mode 100644
index 0000000..9c296e2
--- /dev/null
+++ b/linux-bsp/asm-study/yaffs2/yaffs2/yaffs_guts.c
@@ -0,0 +1,5053 @@
+/*
+ * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
+ *
+ * Copyright (C) 2002-2011 Aleph One Ltd.
+ *   for Toby Churchill Ltd and Brightstar Engineering
+ *
+ * Created by Charles Manning <charles@aleph1.co.uk>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include "yportenv.h"
+#include "yaffs_trace.h"
+
+#include "yaffs_guts.h"
+#include "yaffs_getblockinfo.h"
+#include "yaffs_tagscompat.h"
+#include "yaffs_nand.h"
+#include "yaffs_yaffs1.h"
+#include "yaffs_yaffs2.h"
+#include "yaffs_bitmap.h"
+#include "yaffs_verify.h"
+#include "yaffs_nand.h"
+#include "yaffs_packedtags2.h"
+#include "yaffs_nameval.h"
+#include "yaffs_allocator.h"
+#include "yaffs_attribs.h"
+#include "yaffs_summary.h"
+
+/* Note YAFFS_GC_GOOD_ENOUGH must be <= YAFFS_GC_PASSIVE_THRESHOLD */
+#define YAFFS_GC_GOOD_ENOUGH 2
+#define YAFFS_GC_PASSIVE_THRESHOLD 4
+
+#include "yaffs_ecc.h"
+
+/* Forward declarations */
+
+static int yaffs_wr_data_obj(struct yaffs_obj *in, int inode_chunk,
+			     const u8 *buffer, int n_bytes, int use_reserve);
+
+static void yaffs_fix_null_name(struct yaffs_obj *obj, YCHAR *name,
+				int buffer_size);
+
+/* Function to calculate chunk and offset */
+
+void yaffs_addr_to_chunk(struct yaffs_dev *dev, loff_t addr,
+				int *chunk_out, u32 *offset_out)
+{
+	int chunk;
+	u32 offset;
+
+	chunk = (u32) (addr >> dev->chunk_shift);
+
+	if (dev->chunk_div == 1) {
+		/* easy power of 2 case */
+		offset = (u32) (addr & dev->chunk_mask);
+	} else {
+		/* Non power-of-2 case */
+
+		loff_t chunk_base;
+
+		chunk /= dev->chunk_div;
+
+		chunk_base = ((loff_t) chunk) * dev->data_bytes_per_chunk;
+		offset = (u32) (addr - chunk_base);
+	}
+
+	*chunk_out = chunk;
+	*offset_out = offset;
+}
+
+/* Function to return the number of shifts for a power of 2 greater than or
+ * equal to the given number
+ * Note we don't try to cater for all possible numbers and this does not have to
+ * be hellishly efficient.
+ */
+
+static inline u32 calc_shifts_ceiling(u32 x)
+{
+	int extra_bits;
+	int shifts;
+
+	shifts = extra_bits = 0;
+
+	while (x > 1) {
+		if (x & 1)
+			extra_bits++;
+		x >>= 1;
+		shifts++;
+	}
+
+	if (extra_bits)
+		shifts++;
+
+	return shifts;
+}
+
+/* Function to return the number of shifts to get a 1 in bit 0
+ */
+
+static inline u32 calc_shifts(u32 x)
+{
+	u32 shifts;
+
+	shifts = 0;
+
+	if (!x)
+		return 0;
+
+	while (!(x & 1)) {
+		x >>= 1;
+		shifts++;
+	}
+
+	return shifts;
+}
+
+/*
+ * Temporary buffer manipulations.
+ */
+
+static int yaffs_init_tmp_buffers(struct yaffs_dev *dev)
+{
+	int i;
+	u8 *buf = (u8 *) 1;
+
+	memset(dev->temp_buffer, 0, sizeof(dev->temp_buffer));
+
+	for (i = 0; buf && i < YAFFS_N_TEMP_BUFFERS; i++) {
+		dev->temp_buffer[i].in_use = 0;
+		buf = kmalloc(dev->param.total_bytes_per_chunk, GFP_NOFS);
+		dev->temp_buffer[i].buffer = buf;
+	}
+
+	return buf ? YAFFS_OK : YAFFS_FAIL;
+}
+
+u8 *yaffs_get_temp_buffer(struct yaffs_dev * dev)
+{
+	int i;
+
+	dev->temp_in_use++;
+	if (dev->temp_in_use > dev->max_temp)
+		dev->max_temp = dev->temp_in_use;
+
+	for (i = 0; i < YAFFS_N_TEMP_BUFFERS; i++) {
+		if (dev->temp_buffer[i].in_use == 0) {
+			dev->temp_buffer[i].in_use = 1;
+			return dev->temp_buffer[i].buffer;
+		}
+	}
+
+	yaffs_trace(YAFFS_TRACE_BUFFERS, "Out of temp buffers");
+	/*
+	 * If we got here then we have to allocate an unmanaged one
+	 * This is not good.
+	 */
+
+	dev->unmanaged_buffer_allocs++;
+	return kmalloc(dev->data_bytes_per_chunk, GFP_NOFS);
+
+}
+
+void yaffs_release_temp_buffer(struct yaffs_dev *dev, u8 *buffer)
+{
+	int i;
+
+	dev->temp_in_use--;
+
+	for (i = 0; i < YAFFS_N_TEMP_BUFFERS; i++) {
+		if (dev->temp_buffer[i].buffer == buffer) {
+			dev->temp_buffer[i].in_use = 0;
+			return;
+		}
+	}
+
+	if (buffer) {
+		/* assume it is an unmanaged one. */
+		yaffs_trace(YAFFS_TRACE_BUFFERS,
+			"Releasing unmanaged temp buffer");
+		kfree(buffer);
+		dev->unmanaged_buffer_deallocs++;
+	}
+
+}
+
+/*
+ * Functions for robustisizing TODO
+ *
+ */
+
+static void yaffs_handle_chunk_wr_ok(struct yaffs_dev *dev, int nand_chunk,
+				     const u8 *data,
+				     const struct yaffs_ext_tags *tags)
+{
+	(void) dev;
+	(void) nand_chunk;
+	(void) data;
+	(void) tags;
+}
+
+static void yaffs_handle_chunk_update(struct yaffs_dev *dev, int nand_chunk,
+				      const struct yaffs_ext_tags *tags)
+{
+	(void) dev;
+	(void) nand_chunk;
+	(void) tags;
+}
+
+void yaffs_handle_chunk_error(struct yaffs_dev *dev,
+			      struct yaffs_block_info *bi)
+{
+	if (!bi->gc_prioritise) {
+		bi->gc_prioritise = 1;
+		dev->has_pending_prioritised_gc = 1;
+		bi->chunk_error_strikes++;
+
+		if (bi->chunk_error_strikes > 3) {
+			bi->needs_retiring = 1;	/* Too many stikes, so retire */
+			yaffs_trace(YAFFS_TRACE_ALWAYS,
+				"yaffs: Block struck out");
+
+		}
+	}
+}
+
+static void yaffs_handle_chunk_wr_error(struct yaffs_dev *dev, int nand_chunk,
+					int erased_ok)
+{
+	int flash_block = nand_chunk / dev->param.chunks_per_block;
+	struct yaffs_block_info *bi = yaffs_get_block_info(dev, flash_block);
+
+	yaffs_handle_chunk_error(dev, bi);
+
+	if (erased_ok) {
+		/* Was an actual write failure,
+		 * so mark the block for retirement.*/
+		bi->needs_retiring = 1;
+		yaffs_trace(YAFFS_TRACE_ERROR | YAFFS_TRACE_BAD_BLOCKS,
+		  "**>> Block %d needs retiring", flash_block);
+	}
+
+	/* Delete the chunk */
+	yaffs_chunk_del(dev, nand_chunk, 1, __LINE__);
+	yaffs_skip_rest_of_block(dev);
+}
+
+/*
+ * Verification code
+ */
+
+/*
+ *  Simple hash function. Needs to have a reasonable spread
+ */
+
+static inline int yaffs_hash_fn(int n)
+{
+	if (n < 0)
+		n = -n;
+	return n % YAFFS_NOBJECT_BUCKETS;
+}
+
+/*
+ * Access functions to useful fake objects.
+ * Note that root might have a presence in NAND if permissions are set.
+ */
+
+struct yaffs_obj *yaffs_root(struct yaffs_dev *dev)
+{
+	return dev->root_dir;
+}
+
+struct yaffs_obj *yaffs_lost_n_found(struct yaffs_dev *dev)
+{
+	return dev->lost_n_found;
+}
+
+/*
+ *  Erased NAND checking functions
+ */
+
+int yaffs_check_ff(u8 *buffer, int n_bytes)
+{
+	/* Horrible, slow implementation */
+	while (n_bytes--) {
+		if (*buffer != 0xff)
+			return 0;
+		buffer++;
+	}
+	return 1;
+}
+
+static int yaffs_check_chunk_erased(struct yaffs_dev *dev, int nand_chunk)
+{
+	int retval = YAFFS_OK;
+	u8 *data = yaffs_get_temp_buffer(dev);
+	struct yaffs_ext_tags tags;
+	int result;
+
+	result = yaffs_rd_chunk_tags_nand(dev, nand_chunk, data, &tags);
+
+	if (tags.ecc_result > YAFFS_ECC_RESULT_NO_ERROR)
+		retval = YAFFS_FAIL;
+
+	if (!yaffs_check_ff(data, dev->data_bytes_per_chunk) ||
+		tags.chunk_used) {
+		yaffs_trace(YAFFS_TRACE_NANDACCESS,
+			"Chunk %d not erased", nand_chunk);
+		retval = YAFFS_FAIL;
+	}
+
+	yaffs_release_temp_buffer(dev, data);
+
+	return retval;
+
+}
+
+static int yaffs_verify_chunk_written(struct yaffs_dev *dev,
+				      int nand_chunk,
+				      const u8 *data,
+				      struct yaffs_ext_tags *tags)
+{
+	int retval = YAFFS_OK;
+	struct yaffs_ext_tags temp_tags;
+	u8 *buffer = yaffs_get_temp_buffer(dev);
+	int result;
+
+	result = yaffs_rd_chunk_tags_nand(dev, nand_chunk, buffer, &temp_tags);
+	if (memcmp(buffer, data, dev->data_bytes_per_chunk) ||
+	    temp_tags.obj_id != tags->obj_id ||
+	    temp_tags.chunk_id != tags->chunk_id ||
+	    temp_tags.n_bytes != tags->n_bytes)
+		retval = YAFFS_FAIL;
+
+	yaffs_release_temp_buffer(dev, buffer);
+
+	return retval;
+}
+
+
+int yaffs_check_alloc_available(struct yaffs_dev *dev, int n_chunks)
+{
+	int reserved_chunks;
+	int reserved_blocks = dev->param.n_reserved_blocks;
+	int checkpt_blocks;
+
+	checkpt_blocks = yaffs_calc_checkpt_blocks_required(dev);
+
+	reserved_chunks =
+	    (reserved_blocks + checkpt_blocks) * dev->param.chunks_per_block;
+
+	return (dev->n_free_chunks > (reserved_chunks + n_chunks));
+}
+
+static int yaffs_find_alloc_block(struct yaffs_dev *dev)
+{
+	int i;
+	struct yaffs_block_info *bi;
+
+	if (dev->n_erased_blocks < 1) {
+		/* Hoosterman we've got a problem.
+		 * Can't get space to gc
+		 */
+		yaffs_trace(YAFFS_TRACE_ERROR,
+		  "yaffs tragedy: no more erased blocks");
+
+		return -1;
+	}
+
+	/* Find an empty block. */
+
+	for (i = dev->internal_start_block; i <= dev->internal_end_block; i++) {
+		dev->alloc_block_finder++;
+		if (dev->alloc_block_finder < dev->internal_start_block
+		    || dev->alloc_block_finder > dev->internal_end_block) {
+			dev->alloc_block_finder = dev->internal_start_block;
+		}
+
+		bi = yaffs_get_block_info(dev, dev->alloc_block_finder);
+
+		if (bi->block_state == YAFFS_BLOCK_STATE_EMPTY) {
+			bi->block_state = YAFFS_BLOCK_STATE_ALLOCATING;
+			dev->seq_number++;
+			bi->seq_number = dev->seq_number;
+			dev->n_erased_blocks--;
+			yaffs_trace(YAFFS_TRACE_ALLOCATE,
+			  "Allocated block %d, seq  %d, %d left" ,
+			   dev->alloc_block_finder, dev->seq_number,
+			   dev->n_erased_blocks);
+			return dev->alloc_block_finder;
+		}
+	}
+
+	yaffs_trace(YAFFS_TRACE_ALWAYS,
+		"yaffs tragedy: no more erased blocks, but there should have been %d",
+		dev->n_erased_blocks);
+
+	return -1;
+}
+
+static int yaffs_alloc_chunk(struct yaffs_dev *dev, int use_reserver,
+			     struct yaffs_block_info **block_ptr)
+{
+	int ret_val;
+	struct yaffs_block_info *bi;
+
+	if (dev->alloc_block < 0) {
+		/* Get next block to allocate off */
+		dev->alloc_block = yaffs_find_alloc_block(dev);
+		dev->alloc_page = 0;
+	}
+
+	if (!use_reserver && !yaffs_check_alloc_available(dev, 1)) {
+		/* No space unless we're allowed to use the reserve. */
+		return -1;
+	}
+
+	if (dev->n_erased_blocks < dev->param.n_reserved_blocks
+	    && dev->alloc_page == 0)
+		yaffs_trace(YAFFS_TRACE_ALLOCATE, "Allocating reserve");
+
+	/* Next page please.... */
+	if (dev->alloc_block >= 0) {
+		bi = yaffs_get_block_info(dev, dev->alloc_block);
+
+		ret_val = (dev->alloc_block * dev->param.chunks_per_block) +
+		    dev->alloc_page;
+		bi->pages_in_use++;
+		yaffs_set_chunk_bit(dev, dev->alloc_block, dev->alloc_page);
+
+		dev->alloc_page++;
+
+		dev->n_free_chunks--;
+
+		/* If the block is full set the state to full */
+		if (dev->alloc_page >= dev->param.chunks_per_block) {
+			bi->block_state = YAFFS_BLOCK_STATE_FULL;
+			dev->alloc_block = -1;
+		}
+
+		if (block_ptr)
+			*block_ptr = bi;
+
+		return ret_val;
+	}
+
+	yaffs_trace(YAFFS_TRACE_ERROR,
+		"!!!!!!!!! Allocator out !!!!!!!!!!!!!!!!!");
+
+	return -1;
+}
+
+static int yaffs_get_erased_chunks(struct yaffs_dev *dev)
+{
+	int n;
+
+	n = dev->n_erased_blocks * dev->param.chunks_per_block;
+
+	if (dev->alloc_block > 0)
+		n += (dev->param.chunks_per_block - dev->alloc_page);
+
+	return n;
+
+}
+
+/*
+ * yaffs_skip_rest_of_block() skips over the rest of the allocation block
+ * if we don't want to write to it.
+ */
+void yaffs_skip_rest_of_block(struct yaffs_dev *dev)
+{
+	struct yaffs_block_info *bi;
+
+	if (dev->alloc_block > 0) {
+		bi = yaffs_get_block_info(dev, dev->alloc_block);
+		if (bi->block_state == YAFFS_BLOCK_STATE_ALLOCATING) {
+			bi->block_state = YAFFS_BLOCK_STATE_FULL;
+			dev->alloc_block = -1;
+		}
+	}
+}
+
+static int yaffs_write_new_chunk(struct yaffs_dev *dev,
+				 const u8 *data,
+				 struct yaffs_ext_tags *tags, int use_reserver)
+{
+	int attempts = 0;
+	int write_ok = 0;
+	int chunk;
+
+	yaffs2_checkpt_invalidate(dev);
+
+	do {
+		struct yaffs_block_info *bi = 0;
+		int erased_ok = 0;
+
+		chunk = yaffs_alloc_chunk(dev, use_reserver, &bi);
+		if (chunk < 0) {
+			/* no space */
+			break;
+		}
+
+		/* First check this chunk is erased, if it needs
+		 * checking.  The checking policy (unless forced
+		 * always on) is as follows:
+		 *
+		 * Check the first page we try to write in a block.
+		 * If the check passes then we don't need to check any
+		 * more.        If the check fails, we check again...
+		 * If the block has been erased, we don't need to check.
+		 *
+		 * However, if the block has been prioritised for gc,
+		 * then we think there might be something odd about
+		 * this block and stop using it.
+		 *
+		 * Rationale: We should only ever see chunks that have
+		 * not been erased if there was a partially written
+		 * chunk due to power loss.  This checking policy should
+		 * catch that case with very few checks and thus save a
+		 * lot of checks that are most likely not needed.
+		 *
+		 * Mods to the above
+		 * If an erase check fails or the write fails we skip the
+		 * rest of the block.
+		 */
+
+		/* let's give it a try */
+		attempts++;
+
+		if (dev->param.always_check_erased)
+			bi->skip_erased_check = 0;
+
+		if (!bi->skip_erased_check) {
+			erased_ok = yaffs_check_chunk_erased(dev, chunk);
+			if (erased_ok != YAFFS_OK) {
+				yaffs_trace(YAFFS_TRACE_ERROR,
+				  "**>> yaffs chunk %d was not erased",
+				  chunk);
+
+				/* If not erased, delete this one,
+				 * skip rest of block and
+				 * try another chunk */
+				yaffs_chunk_del(dev, chunk, 1, __LINE__);
+				yaffs_skip_rest_of_block(dev);
+				continue;
+			}
+		}
+
+		write_ok = yaffs_wr_chunk_tags_nand(dev, chunk, data, tags);
+
+		if (!bi->skip_erased_check)
+			write_ok =
+			    yaffs_verify_chunk_written(dev, chunk, data, tags);
+
+		if (write_ok != YAFFS_OK) {
+			/* Clean up aborted write, skip to next block and
+			 * try another chunk */
+			yaffs_handle_chunk_wr_error(dev, chunk, erased_ok);
+			continue;
+		}
+
+		bi->skip_erased_check = 1;
+
+		/* Copy the data into the robustification buffer */
+		yaffs_handle_chunk_wr_ok(dev, chunk, data, tags);
+
+	} while (write_ok != YAFFS_OK &&
+		 (yaffs_wr_attempts <= 0 || attempts <= yaffs_wr_attempts));
+
+	if (!write_ok)
+		chunk = -1;
+
+	if (attempts > 1) {
+		yaffs_trace(YAFFS_TRACE_ERROR,
+			"**>> yaffs write required %d attempts",
+			attempts);
+		dev->n_retried_writes += (attempts - 1);
+	}
+
+	return chunk;
+}
+
+/*
+ * Block retiring for handling a broken block.
+ */
+
+static void yaffs_retire_block(struct yaffs_dev *dev, int flash_block)
+{
+	struct yaffs_block_info *bi = yaffs_get_block_info(dev, flash_block);
+
+	yaffs2_checkpt_invalidate(dev);
+
+	yaffs2_clear_oldest_dirty_seq(dev, bi);
+
+	if (yaffs_mark_bad(dev, flash_block) != YAFFS_OK) {
+		if (yaffs_erase_block(dev, flash_block) != YAFFS_OK) {
+			yaffs_trace(YAFFS_TRACE_ALWAYS,
+				"yaffs: Failed to mark bad and erase block %d",
+				flash_block);
+		} else {
+			struct yaffs_ext_tags tags;
+			int chunk_id =
+			    flash_block * dev->param.chunks_per_block;
+
+			u8 *buffer = yaffs_get_temp_buffer(dev);
+
+			memset(buffer, 0xff, dev->data_bytes_per_chunk);
+			memset(&tags, 0, sizeof(tags));
+			tags.seq_number = YAFFS_SEQUENCE_BAD_BLOCK;
+			if (dev->param.write_chunk_tags_fn(dev, chunk_id -
+							   dev->chunk_offset,
+							   buffer,
+							   &tags) != YAFFS_OK)
+				yaffs_trace(YAFFS_TRACE_ALWAYS,
+					"yaffs: Failed to write bad block marker to block %d",
+					flash_block);
+
+			yaffs_release_temp_buffer(dev, buffer);
+		}
+	}
+
+	bi->block_state = YAFFS_BLOCK_STATE_DEAD;
+	bi->gc_prioritise = 0;
+	bi->needs_retiring = 0;
+
+	dev->n_retired_blocks++;
+}
+
+/*---------------- Name handling functions ------------*/
+
+static u16 yaffs_calc_name_sum(const YCHAR *name)
+{
+	u16 sum = 0;
+	u16 i = 1;
+
+	if (!name)
+		return 0;
+
+	while ((*name) && i < (YAFFS_MAX_NAME_LENGTH / 2)) {
+
+		/* 0x1f mask is case insensitive */
+		sum += ((*name) & 0x1f) * i;
+		i++;
+		name++;
+	}
+	return sum;
+}
+
+
+void yaffs_set_obj_name(struct yaffs_obj *obj, const YCHAR * name)
+{
+	memset(obj->short_name, 0, sizeof(obj->short_name));
+
+	if (name && !name[0]) {
+		yaffs_fix_null_name(obj, obj->short_name,
+				YAFFS_SHORT_NAME_LENGTH);
+		name = obj->short_name;
+	} else if (name &&
+		strnlen(name, YAFFS_SHORT_NAME_LENGTH + 1) <=
+		YAFFS_SHORT_NAME_LENGTH)  {
+		strcpy(obj->short_name, name);
+	}
+
+	obj->sum = yaffs_calc_name_sum(name);
+}
+
+void yaffs_set_obj_name_from_oh(struct yaffs_obj *obj,
+				const struct yaffs_obj_hdr *oh)
+{
+#ifdef CONFIG_YAFFS_AUTO_UNICODE
+	YCHAR tmp_name[YAFFS_MAX_NAME_LENGTH + 1];
+	memset(tmp_name, 0, sizeof(tmp_name));
+	yaffs_load_name_from_oh(obj->my_dev, tmp_name, oh->name,
+				YAFFS_MAX_NAME_LENGTH + 1);
+	yaffs_set_obj_name(obj, tmp_name);
+#else
+	yaffs_set_obj_name(obj, oh->name);
+#endif
+}
+
+loff_t yaffs_max_file_size(struct yaffs_dev *dev)
+{
+	if(sizeof(loff_t) < 8)
+		return YAFFS_MAX_FILE_SIZE_32;
+	else
+		return ((loff_t) YAFFS_MAX_CHUNK_ID) * dev->data_bytes_per_chunk;
+}
+
+/*-------------------- TNODES -------------------
+
+ * List of spare tnodes
+ * The list is hooked together using the first pointer
+ * in the tnode.
+ */
+
+struct yaffs_tnode *yaffs_get_tnode(struct yaffs_dev *dev)
+{
+	struct yaffs_tnode *tn = yaffs_alloc_raw_tnode(dev);
+
+	if (tn) {
+		memset(tn, 0, dev->tnode_size);
+		dev->n_tnodes++;
+	}
+
+	dev->checkpoint_blocks_required = 0;	/* force recalculation */
+
+	return tn;
+}
+
+/* FreeTnode frees up a tnode and puts it back on the free list */
+static void yaffs_free_tnode(struct yaffs_dev *dev, struct yaffs_tnode *tn)
+{
+	yaffs_free_raw_tnode(dev, tn);
+	dev->n_tnodes--;
+	dev->checkpoint_blocks_required = 0;	/* force recalculation */
+}
+
+static void yaffs_deinit_tnodes_and_objs(struct yaffs_dev *dev)
+{
+	yaffs_deinit_raw_tnodes_and_objs(dev);
+	dev->n_obj = 0;
+	dev->n_tnodes = 0;
+}
+
+static void yaffs_load_tnode_0(struct yaffs_dev *dev, struct yaffs_tnode *tn,
+			unsigned pos, unsigned val)
+{
+	u32 *map = (u32 *) tn;
+	u32 bit_in_map;
+	u32 bit_in_word;
+	u32 word_in_map;
+	u32 mask;
+
+	pos &= YAFFS_TNODES_LEVEL0_MASK;
+	val >>= dev->chunk_grp_bits;
+
+	bit_in_map = pos * dev->tnode_width;
+	word_in_map = bit_in_map / 32;
+	bit_in_word = bit_in_map & (32 - 1);
+
+	mask = dev->tnode_mask << bit_in_word;
+
+	map[word_in_map] &= ~mask;
+	map[word_in_map] |= (mask & (val << bit_in_word));
+
+	if (dev->tnode_width > (32 - bit_in_word)) {
+		bit_in_word = (32 - bit_in_word);
+		word_in_map++;
+		mask =
+		    dev->tnode_mask >> bit_in_word;
+		map[word_in_map] &= ~mask;
+		map[word_in_map] |= (mask & (val >> bit_in_word));
+	}
+}
+
+u32 yaffs_get_group_base(struct yaffs_dev *dev, struct yaffs_tnode *tn,
+			 unsigned pos)
+{
+	u32 *map = (u32 *) tn;
+	u32 bit_in_map;
+	u32 bit_in_word;
+	u32 word_in_map;
+	u32 val;
+
+	pos &= YAFFS_TNODES_LEVEL0_MASK;
+
+	bit_in_map = pos * dev->tnode_width;
+	word_in_map = bit_in_map / 32;
+	bit_in_word = bit_in_map & (32 - 1);
+
+	val = map[word_in_map] >> bit_in_word;
+
+	if (dev->tnode_width > (32 - bit_in_word)) {
+		bit_in_word = (32 - bit_in_word);
+		word_in_map++;
+		val |= (map[word_in_map] << bit_in_word);
+	}
+
+	val &= dev->tnode_mask;
+	val <<= dev->chunk_grp_bits;
+
+	return val;
+}
+
+/* ------------------- End of individual tnode manipulation -----------------*/
+
+/* ---------Functions to manipulate the look-up tree (made up of tnodes) ------
+ * The look up tree is represented by the top tnode and the number of top_level
+ * in the tree. 0 means only the level 0 tnode is in the tree.
+ */
+
+/* FindLevel0Tnode finds the level 0 tnode, if one exists. */
+struct yaffs_tnode *yaffs_find_tnode_0(struct yaffs_dev *dev,
+				       struct yaffs_file_var *file_struct,
+				       u32 chunk_id)
+{
+	struct yaffs_tnode *tn = file_struct->top;
+	u32 i;
+	int required_depth;
+	int level = file_struct->top_level;
+
+	(void) dev;
+
+	/* Check sane level and chunk Id */
+	if (level < 0 || level > YAFFS_TNODES_MAX_LEVEL)
+		return NULL;
+
+	if (chunk_id > YAFFS_MAX_CHUNK_ID)
+		return NULL;
+
+	/* First check we're tall enough (ie enough top_level) */
+
+	i = chunk_id >> YAFFS_TNODES_LEVEL0_BITS;
+	required_depth = 0;
+	while (i) {
+		i >>= YAFFS_TNODES_INTERNAL_BITS;
+		required_depth++;
+	}
+
+	if (required_depth > file_struct->top_level)
+		return NULL;	/* Not tall enough, so we can't find it */
+
+	/* Traverse down to level 0 */
+	while (level > 0 && tn) {
+		tn = tn->internal[(chunk_id >>
+				   (YAFFS_TNODES_LEVEL0_BITS +
+				    (level - 1) *
+				    YAFFS_TNODES_INTERNAL_BITS)) &
+				  YAFFS_TNODES_INTERNAL_MASK];
+		level--;
+	}
+
+	return tn;
+}
+
+/* add_find_tnode_0 finds the level 0 tnode if it exists,
+ * otherwise first expands the tree.
+ * This happens in two steps:
+ *  1. If the tree isn't tall enough, then make it taller.
+ *  2. Scan down the tree towards the level 0 tnode adding tnodes if required.
+ *
+ * Used when modifying the tree.
+ *
+ *  If the tn argument is NULL, then a fresh tnode will be added otherwise the
+ *  specified tn will be plugged into the ttree.
+ */
+
+struct yaffs_tnode *yaffs_add_find_tnode_0(struct yaffs_dev *dev,
+					   struct yaffs_file_var *file_struct,
+					   u32 chunk_id,
+					   struct yaffs_tnode *passed_tn)
+{
+	int required_depth;
+	int i;
+	int l;
+	struct yaffs_tnode *tn;
+	u32 x;
+
+	/* Check sane level and page Id */
+	if (file_struct->top_level < 0 ||
+	    file_struct->top_level > YAFFS_TNODES_MAX_LEVEL)
+		return NULL;
+
+	if (chunk_id > YAFFS_MAX_CHUNK_ID)
+		return NULL;
+
+	/* First check we're tall enough (ie enough top_level) */
+
+	x = chunk_id >> YAFFS_TNODES_LEVEL0_BITS;
+	required_depth = 0;
+	while (x) {
+		x >>= YAFFS_TNODES_INTERNAL_BITS;
+		required_depth++;
+	}
+
+	if (required_depth > file_struct->top_level) {
+		/* Not tall enough, gotta make the tree taller */
+		for (i = file_struct->top_level; i < required_depth; i++) {
+
+			tn = yaffs_get_tnode(dev);
+
+			if (tn) {
+				tn->internal[0] = file_struct->top;
+				file_struct->top = tn;
+				file_struct->top_level++;
+			} else {
+				yaffs_trace(YAFFS_TRACE_ERROR,
+					"yaffs: no more tnodes");
+				return NULL;
+			}
+		}
+	}
+
+	/* Traverse down to level 0, adding anything we need */
+
+	l = file_struct->top_level;
+	tn = file_struct->top;
+
+	if (l > 0) {
+		while (l > 0 && tn) {
+			x = (chunk_id >>
+			     (YAFFS_TNODES_LEVEL0_BITS +
+			      (l - 1) * YAFFS_TNODES_INTERNAL_BITS)) &
+			    YAFFS_TNODES_INTERNAL_MASK;
+
+			if ((l > 1) && !tn->internal[x]) {
+				/* Add missing non-level-zero tnode */
+				tn->internal[x] = yaffs_get_tnode(dev);
+				if (!tn->internal[x])
+					return NULL;
+			} else if (l == 1) {
+				/* Looking from level 1 at level 0 */
+				if (passed_tn) {
+					/* If we already have one, release it */
+					if (tn->internal[x])
+						yaffs_free_tnode(dev,
+							tn->internal[x]);
+					tn->internal[x] = passed_tn;
+
+				} else if (!tn->internal[x]) {
+					/* Don't have one, none passed in */
+					tn->internal[x] = yaffs_get_tnode(dev);
+					if (!tn->internal[x])
+						return NULL;
+				}
+			}
+
+			tn = tn->internal[x];
+			l--;
+		}
+	} else {
+		/* top is level 0 */
+		if (passed_tn) {
+			memcpy(tn, passed_tn,
+			       (dev->tnode_width * YAFFS_NTNODES_LEVEL0) / 8);
+			yaffs_free_tnode(dev, passed_tn);
+		}
+	}
+
+	return tn;
+}
+
+static int yaffs_tags_match(const struct yaffs_ext_tags *tags, int obj_id,
+			    int chunk_obj)
+{
+	return (tags->chunk_id == chunk_obj &&
+		tags->obj_id == obj_id &&
+		!tags->is_deleted) ? 1 : 0;
+
+}
+
+static int yaffs_find_chunk_in_group(struct yaffs_dev *dev, int the_chunk,
+					struct yaffs_ext_tags *tags, int obj_id,
+					int inode_chunk)
+{
+	int j;
+
+	for (j = 0; the_chunk && j < dev->chunk_grp_size; j++) {
+		if (yaffs_check_chunk_bit
+		    (dev, the_chunk / dev->param.chunks_per_block,
+		     the_chunk % dev->param.chunks_per_block)) {
+
+			if (dev->chunk_grp_size == 1)
+				return the_chunk;
+			else {
+				yaffs_rd_chunk_tags_nand(dev, the_chunk, NULL,
+							 tags);
+				if (yaffs_tags_match(tags,
+							obj_id, inode_chunk)) {
+					/* found it; */
+					return the_chunk;
+				}
+			}
+		}
+		the_chunk++;
+	}
+	return -1;
+}
+
+static int yaffs_find_chunk_in_file(struct yaffs_obj *in, int inode_chunk,
+				    struct yaffs_ext_tags *tags)
+{
+	/*Get the Tnode, then get the level 0 offset chunk offset */
+	struct yaffs_tnode *tn;
+	int the_chunk = -1;
+	struct yaffs_ext_tags local_tags;
+	int ret_val = -1;
+	struct yaffs_dev *dev = in->my_dev;
+
+	if (!tags) {
+		/* Passed a NULL, so use our own tags space */
+		tags = &local_tags;
+	}
+
+	tn = yaffs_find_tnode_0(dev, &in->variant.file_variant, inode_chunk);
+
+	if (!tn)
+		return ret_val;
+
+	the_chunk = yaffs_get_group_base(dev, tn, inode_chunk);
+
+	ret_val = yaffs_find_chunk_in_group(dev, the_chunk, tags, in->obj_id,
+					      inode_chunk);
+	return ret_val;
+}
+
+static int yaffs_find_del_file_chunk(struct yaffs_obj *in, int inode_chunk,
+				     struct yaffs_ext_tags *tags)
+{
+	/* Get the Tnode, then get the level 0 offset chunk offset */
+	struct yaffs_tnode *tn;
+	int the_chunk = -1;
+	struct yaffs_ext_tags local_tags;
+	struct yaffs_dev *dev = in->my_dev;
+	int ret_val = -1;
+
+	if (!tags) {
+		/* Passed a NULL, so use our own tags space */
+		tags = &local_tags;
+	}
+
+	tn = yaffs_find_tnode_0(dev, &in->variant.file_variant, inode_chunk);
+
+	if (!tn)
+		return ret_val;
+
+	the_chunk = yaffs_get_group_base(dev, tn, inode_chunk);
+
+	ret_val = yaffs_find_chunk_in_group(dev, the_chunk, tags, in->obj_id,
+					      inode_chunk);
+
+	/* Delete the entry in the filestructure (if found) */
+	if (ret_val != -1)
+		yaffs_load_tnode_0(dev, tn, inode_chunk, 0);
+
+	return ret_val;
+}
+
+int yaffs_put_chunk_in_file(struct yaffs_obj *in, int inode_chunk,
+			    int nand_chunk, int in_scan)
+{
+	/* NB in_scan is zero unless scanning.
+	 * For forward scanning, in_scan is > 0;
+	 * for backward scanning in_scan is < 0
+	 *
+	 * nand_chunk = 0 is a dummy insert to make sure the tnodes are there.
+	 */
+
+	struct yaffs_tnode *tn;
+	struct yaffs_dev *dev = in->my_dev;
+	int existing_cunk;
+	struct yaffs_ext_tags existing_tags;
+	struct yaffs_ext_tags new_tags;
+	unsigned existing_serial, new_serial;
+
+	if (in->variant_type != YAFFS_OBJECT_TYPE_FILE) {
+		/* Just ignore an attempt at putting a chunk into a non-file
+		 * during scanning.
+		 * If it is not during Scanning then something went wrong!
+		 */
+		if (!in_scan) {
+			yaffs_trace(YAFFS_TRACE_ERROR,
+				"yaffs tragedy:attempt to put data chunk into a non-file"
+				);
+			BUG();
+		}
+
+		yaffs_chunk_del(dev, nand_chunk, 1, __LINE__);
+		return YAFFS_OK;
+	}
+
+	tn = yaffs_add_find_tnode_0(dev,
+				    &in->variant.file_variant,
+				    inode_chunk, NULL);
+	if (!tn)
+		return YAFFS_FAIL;
+
+	if (!nand_chunk)
+		/* Dummy insert, bail now */
+		return YAFFS_OK;
+
+	existing_cunk = yaffs_get_group_base(dev, tn, inode_chunk);
+
+	if (in_scan != 0) {
+		/* If we're scanning then we need to test for duplicates
+		 * NB This does not need to be efficient since it should only
+		 * happen when the power fails during a write, then only one
+		 * chunk should ever be affected.
+		 *
+		 * Correction for YAFFS2: This could happen quite a lot and we
+		 * need to think about efficiency! TODO
+		 * Update: For backward scanning we don't need to re-read tags
+		 * so this is quite cheap.
+		 */
+
+		if (existing_cunk > 0) {
+			/* NB Right now existing chunk will not be real
+			 * chunk_id if the chunk group size > 1
+			 * thus we have to do a FindChunkInFile to get the
+			 * real chunk id.
+			 *
+			 * We have a duplicate now we need to decide which
+			 * one to use:
+			 *
+			 * Backwards scanning YAFFS2: The old one is what
+			 * we use, dump the new one.
+			 * YAFFS1: Get both sets of tags and compare serial
+			 * numbers.
+			 */
+
+			if (in_scan > 0) {
+				/* Only do this for forward scanning */
+				yaffs_rd_chunk_tags_nand(dev,
+							 nand_chunk,
+							 NULL, &new_tags);
+
+				/* Do a proper find */
+				existing_cunk =
+				    yaffs_find_chunk_in_file(in, inode_chunk,
+							     &existing_tags);
+			}
+
+			if (existing_cunk <= 0) {
+				/*Hoosterman - how did this happen? */
+
+				yaffs_trace(YAFFS_TRACE_ERROR,
+					"yaffs tragedy: existing chunk < 0 in scan"
+					);
+
+			}
+
+			/* NB The deleted flags should be false, otherwise
+			 * the chunks will not be loaded during a scan
+			 */
+
+			if (in_scan > 0) {
+				new_serial = new_tags.serial_number;
+				existing_serial = existing_tags.serial_number;
+			}
+
+			if ((in_scan > 0) &&
+			    (existing_cunk <= 0 ||
+			     ((existing_serial + 1) & 3) == new_serial)) {
+				/* Forward scanning.
+				 * Use new
+				 * Delete the old one and drop through to
+				 * update the tnode
+				 */
+				yaffs_chunk_del(dev, existing_cunk, 1,
+						__LINE__);
+			} else {
+				/* Backward scanning or we want to use the
+				 * existing one
+				 * Delete the new one and return early so that
+				 * the tnode isn't changed
+				 */
+				yaffs_chunk_del(dev, nand_chunk, 1, __LINE__);
+				return YAFFS_OK;
+			}
+		}
+
+	}
+
+	if (existing_cunk == 0)
+		in->n_data_chunks++;
+
+	yaffs_load_tnode_0(dev, tn, inode_chunk, nand_chunk);
+
+	return YAFFS_OK;
+}
+
+static void yaffs_soft_del_chunk(struct yaffs_dev *dev, int chunk)
+{
+	struct yaffs_block_info *the_block;
+	unsigned block_no;
+
+	yaffs_trace(YAFFS_TRACE_DELETION, "soft delete chunk %d", chunk);
+
+	block_no = chunk / dev->param.chunks_per_block;
+	the_block = yaffs_get_block_info(dev, block_no);
+	if (the_block) {
+		the_block->soft_del_pages++;
+		dev->n_free_chunks++;
+		yaffs2_update_oldest_dirty_seq(dev, block_no, the_block);
+	}
+}
+
+/* SoftDeleteWorker scans backwards through the tnode tree and soft deletes all
+ * the chunks in the file.
+ * All soft deleting does is increment the block's softdelete count and pulls
+ * the chunk out of the tnode.
+ * Thus, essentially this is the same as DeleteWorker except that the chunks
+ * are soft deleted.
+ */
+
+static int yaffs_soft_del_worker(struct yaffs_obj *in, struct yaffs_tnode *tn,
+				 u32 level, int chunk_offset)
+{
+	int i;
+	int the_chunk;
+	int all_done = 1;
+	struct yaffs_dev *dev = in->my_dev;
+
+	if (!tn)
+		return 1;
+
+	if (level > 0) {
+		for (i = YAFFS_NTNODES_INTERNAL - 1;
+			all_done && i >= 0;
+			i--) {
+			if (tn->internal[i]) {
+				all_done =
+				    yaffs_soft_del_worker(in,
+					tn->internal[i],
+					level - 1,
+					(chunk_offset <<
+					YAFFS_TNODES_INTERNAL_BITS)
+					+ i);
+				if (all_done) {
+					yaffs_free_tnode(dev,
+						tn->internal[i]);
+					tn->internal[i] = NULL;
+				} else {
+					/* Can this happen? */
+				}
+			}
+		}
+		return (all_done) ? 1 : 0;
+	}
+
+	/* level 0 */
+	 for (i = YAFFS_NTNODES_LEVEL0 - 1; i >= 0; i--) {
+		the_chunk = yaffs_get_group_base(dev, tn, i);
+		if (the_chunk) {
+			yaffs_soft_del_chunk(dev, the_chunk);
+			yaffs_load_tnode_0(dev, tn, i, 0);
+		}
+	}
+	return 1;
+}
+
+static void yaffs_remove_obj_from_dir(struct yaffs_obj *obj)
+{
+	struct yaffs_dev *dev = obj->my_dev;
+	struct yaffs_obj *parent;
+
+	yaffs_verify_obj_in_dir(obj);
+	parent = obj->parent;
+
+	yaffs_verify_dir(parent);
+
+	if (dev && dev->param.remove_obj_fn)
+		dev->param.remove_obj_fn(obj);
+
+	list_del_init(&obj->siblings);
+	obj->parent = NULL;
+
+	yaffs_verify_dir(parent);
+}
+
+void yaffs_add_obj_to_dir(struct yaffs_obj *directory, struct yaffs_obj *obj)
+{
+	if (!directory) {
+		yaffs_trace(YAFFS_TRACE_ALWAYS,
+			"tragedy: Trying to add an object to a null pointer directory"
+			);
+		BUG();
+		return;
+	}
+	if (directory->variant_type != YAFFS_OBJECT_TYPE_DIRECTORY) {
+		yaffs_trace(YAFFS_TRACE_ALWAYS,
+			"tragedy: Trying to add an object to a non-directory"
+			);
+		BUG();
+	}
+
+	if (obj->siblings.prev == NULL) {
+		/* Not initialised */
+		BUG();
+	}
+
+	yaffs_verify_dir(directory);
+
+	yaffs_remove_obj_from_dir(obj);
+
+	/* Now add it */
+	list_add(&obj->siblings, &directory->variant.dir_variant.children);
+	obj->parent = directory;
+
+	if (directory == obj->my_dev->unlinked_dir
+	    || directory == obj->my_dev->del_dir) {
+		obj->unlinked = 1;
+		obj->my_dev->n_unlinked_files++;
+		obj->rename_allowed = 0;
+	}
+
+	yaffs_verify_dir(directory);
+	yaffs_verify_obj_in_dir(obj);
+}
+
+static int yaffs_change_obj_name(struct yaffs_obj *obj,
+				 struct yaffs_obj *new_dir,
+				 const YCHAR *new_name, int force, int shadows)
+{
+	int unlink_op;
+	int del_op;
+	struct yaffs_obj *existing_target;
+
+	if (new_dir == NULL)
+		new_dir = obj->parent;	/* use the old directory */
+
+	if (new_dir->variant_type != YAFFS_OBJECT_TYPE_DIRECTORY) {
+		yaffs_trace(YAFFS_TRACE_ALWAYS,
+			"tragedy: yaffs_change_obj_name: new_dir is not a directory"
+			);
+		BUG();
+	}
+
+	unlink_op = (new_dir == obj->my_dev->unlinked_dir);
+	del_op = (new_dir == obj->my_dev->del_dir);
+
+	existing_target = yaffs_find_by_name(new_dir, new_name);
+
+	/* If the object is a file going into the unlinked directory,
+	 *   then it is OK to just stuff it in since duplicate names are OK.
+	 *   else only proceed if the new name does not exist and we're putting
+	 *   it into a directory.
+	 */
+	if (!(unlink_op || del_op || force ||
+	      shadows > 0 || !existing_target) ||
+	      new_dir->variant_type != YAFFS_OBJECT_TYPE_DIRECTORY)
+		return YAFFS_FAIL;
+
+	yaffs_set_obj_name(obj, new_name);
+	obj->dirty = 1;
+	yaffs_add_obj_to_dir(new_dir, obj);
+
+	if (unlink_op)
+		obj->unlinked = 1;
+
+	/* If it is a deletion then we mark it as a shrink for gc  */
+	if (yaffs_update_oh(obj, new_name, 0, del_op, shadows, NULL) >= 0)
+		return YAFFS_OK;
+
+	return YAFFS_FAIL;
+}
+
+/*------------------------ Short Operations Cache ------------------------------
+ *   In many situations where there is no high level buffering  a lot of
+ *   reads might be short sequential reads, and a lot of writes may be short
+ *   sequential writes. eg. scanning/writing a jpeg file.
+ *   In these cases, a short read/write cache can provide a huge perfomance
+ *   benefit with dumb-as-a-rock code.
+ *   In Linux, the page cache provides read buffering and the short op cache
+ *   provides write buffering.
+ *
+ *   There are a small number (~10) of cache chunks per device so that we don't
+ *   need a very intelligent search.
+ */
+
+static int yaffs_obj_cache_dirty(struct yaffs_obj *obj)
+{
+	struct yaffs_dev *dev = obj->my_dev;
+	int i;
+	struct yaffs_cache *cache;
+	int n_caches = obj->my_dev->param.n_caches;
+
+	for (i = 0; i < n_caches; i++) {
+		cache = &dev->cache[i];
+		if (cache->object == obj && cache->dirty)
+			return 1;
+	}
+
+	return 0;
+}
+
+static void yaffs_flush_file_cache(struct yaffs_obj *obj)
+{
+	struct yaffs_dev *dev = obj->my_dev;
+	int lowest = -99;	/* Stop compiler whining. */
+	int i;
+	struct yaffs_cache *cache;
+	int chunk_written = 0;
+	int n_caches = obj->my_dev->param.n_caches;
+
+	if (n_caches < 1)
+		return;
+	do {
+		cache = NULL;
+
+		/* Find the lowest dirty chunk for this object */
+		for (i = 0; i < n_caches; i++) {
+			if (dev->cache[i].object == obj &&
+			    dev->cache[i].dirty) {
+				if (!cache ||
+				    dev->cache[i].chunk_id < lowest) {
+					cache = &dev->cache[i];
+					lowest = cache->chunk_id;
+				}
+			}
+		}
+
+		if (cache && !cache->locked) {
+			/* Write it out and free it up */
+			chunk_written =
+			    yaffs_wr_data_obj(cache->object,
+					      cache->chunk_id,
+					      cache->data,
+					      cache->n_bytes, 1);
+			cache->dirty = 0;
+			cache->object = NULL;
+		}
+	} while (cache && chunk_written > 0);
+
+	if (cache)
+		/* Hoosterman, disk full while writing cache out. */
+		yaffs_trace(YAFFS_TRACE_ERROR,
+			"yaffs tragedy: no space during cache write");
+}
+
+/*yaffs_flush_whole_cache(dev)
+ *
+ *
+ */
+
+void yaffs_flush_whole_cache(struct yaffs_dev *dev)
+{
+	struct yaffs_obj *obj;
+	int n_caches = dev->param.n_caches;
+	int i;
+
+	/* Find a dirty object in the cache and flush it...
+	 * until there are no further dirty objects.
+	 */
+	do {
+		obj = NULL;
+		for (i = 0; i < n_caches && !obj; i++) {
+			if (dev->cache[i].object && dev->cache[i].dirty)
+				obj = dev->cache[i].object;
+		}
+		if (obj)
+			yaffs_flush_file_cache(obj);
+	} while (obj);
+
+}
+
+/* Grab us a cache chunk for use.
+ * First look for an empty one.
+ * Then look for the least recently used non-dirty one.
+ * Then look for the least recently used dirty one...., flush and look again.
+ */
+static struct yaffs_cache *yaffs_grab_chunk_worker(struct yaffs_dev *dev)
+{
+	int i;
+
+	if (dev->param.n_caches > 0) {
+		for (i = 0; i < dev->param.n_caches; i++) {
+			if (!dev->cache[i].object)
+				return &dev->cache[i];
+		}
+	}
+	return NULL;
+}
+
+static struct yaffs_cache *yaffs_grab_chunk_cache(struct yaffs_dev *dev)
+{
+	struct yaffs_cache *cache;
+	struct yaffs_obj *the_obj;
+	int usage;
+	int i;
+	int pushout;
+
+	if (dev->param.n_caches < 1)
+		return NULL;
+
+	/* Try find a non-dirty one... */
+
+	cache = yaffs_grab_chunk_worker(dev);
+
+	if (!cache) {
+		/* They were all dirty, find the LRU object and flush
+		 * its cache, then  find again.
+		 * NB what's here is not very accurate,
+		 * we actually flush the object with the LRU chunk.
+		 */
+
+		/* With locking we can't assume we can use entry zero,
+		 * Set the_obj to a valid pointer for Coverity. */
+		the_obj = dev->cache[0].object;
+		usage = -1;
+		cache = NULL;
+		pushout = -1;
+
+		for (i = 0; i < dev->param.n_caches; i++) {
+			if (dev->cache[i].object &&
+			    !dev->cache[i].locked &&
+			    (dev->cache[i].last_use < usage ||
+			    !cache)) {
+				usage = dev->cache[i].last_use;
+				the_obj = dev->cache[i].object;
+				cache = &dev->cache[i];
+				pushout = i;
+			}
+		}
+
+		if (!cache || cache->dirty) {
+			/* Flush and try again */
+			yaffs_flush_file_cache(the_obj);
+			cache = yaffs_grab_chunk_worker(dev);
+		}
+	}
+	return cache;
+}
+
+/* Find a cached chunk */
+static struct yaffs_cache *yaffs_find_chunk_cache(const struct yaffs_obj *obj,
+						  int chunk_id)
+{
+	struct yaffs_dev *dev = obj->my_dev;
+	int i;
+
+	if (dev->param.n_caches < 1)
+		return NULL;
+
+	for (i = 0; i < dev->param.n_caches; i++) {
+		if (dev->cache[i].object == obj &&
+		    dev->cache[i].chunk_id == chunk_id) {
+			dev->cache_hits++;
+
+			return &dev->cache[i];
+		}
+	}
+	return NULL;
+}
+
+/* Mark the chunk for the least recently used algorithym */
+static void yaffs_use_cache(struct yaffs_dev *dev, struct yaffs_cache *cache,
+			    int is_write)
+{
+	int i;
+
+	if (dev->param.n_caches < 1)
+		return;
+
+	if (dev->cache_last_use < 0 ||
+		dev->cache_last_use > 100000000) {
+		/* Reset the cache usages */
+		for (i = 1; i < dev->param.n_caches; i++)
+			dev->cache[i].last_use = 0;
+
+		dev->cache_last_use = 0;
+	}
+	dev->cache_last_use++;
+	cache->last_use = dev->cache_last_use;
+
+	if (is_write)
+		cache->dirty = 1;
+}
+
+/* Invalidate a single cache page.
+ * Do this when a whole page gets written,
+ * ie the short cache for this page is no longer valid.
+ */
+static void yaffs_invalidate_chunk_cache(struct yaffs_obj *object, int chunk_id)
+{
+	struct yaffs_cache *cache;
+
+	if (object->my_dev->param.n_caches > 0) {
+		cache = yaffs_find_chunk_cache(object, chunk_id);
+
+		if (cache)
+			cache->object = NULL;
+	}
+}
+
+/* Invalidate all the cache pages associated with this object
+ * Do this whenever ther file is deleted or resized.
+ */
+static void yaffs_invalidate_whole_cache(struct yaffs_obj *in)
+{
+	int i;
+	struct yaffs_dev *dev = in->my_dev;
+
+	if (dev->param.n_caches > 0) {
+		/* Invalidate it. */
+		for (i = 0; i < dev->param.n_caches; i++) {
+			if (dev->cache[i].object == in)
+				dev->cache[i].object = NULL;
+		}
+	}
+}
+
+static void yaffs_unhash_obj(struct yaffs_obj *obj)
+{
+	int bucket;
+	struct yaffs_dev *dev = obj->my_dev;
+
+	/* If it is still linked into the bucket list, free from the list */
+	if (!list_empty(&obj->hash_link)) {
+		list_del_init(&obj->hash_link);
+		bucket = yaffs_hash_fn(obj->obj_id);
+		dev->obj_bucket[bucket].count--;
+	}
+}
+
+/*  FreeObject frees up a Object and puts it back on the free list */
+static void yaffs_free_obj(struct yaffs_obj *obj)
+{
+	struct yaffs_dev *dev;
+
+	if (!obj) {
+		BUG();
+		return;
+	}
+	dev = obj->my_dev;
+	yaffs_trace(YAFFS_TRACE_OS, "FreeObject %p inode %p",
+		obj, obj->my_inode);
+	if (obj->parent)
+		BUG();
+	if (!list_empty(&obj->siblings))
+		BUG();
+
+	if (obj->my_inode) {
+		/* We're still hooked up to a cached inode.
+		 * Don't delete now, but mark for later deletion
+		 */
+		obj->defered_free = 1;
+		return;
+	}
+
+	yaffs_unhash_obj(obj);
+
+	yaffs_free_raw_obj(dev, obj);
+	dev->n_obj--;
+	dev->checkpoint_blocks_required = 0;	/* force recalculation */
+}
+
+void yaffs_handle_defered_free(struct yaffs_obj *obj)
+{
+	if (obj->defered_free)
+		yaffs_free_obj(obj);
+}
+
+static int yaffs_generic_obj_del(struct yaffs_obj *in)
+{
+	/* Iinvalidate the file's data in the cache, without flushing. */
+	yaffs_invalidate_whole_cache(in);
+
+	if (in->my_dev->param.is_yaffs2 && in->parent != in->my_dev->del_dir) {
+		/* Move to unlinked directory so we have a deletion record */
+		yaffs_change_obj_name(in, in->my_dev->del_dir, _Y("deleted"), 0,
+				      0);
+	}
+
+	yaffs_remove_obj_from_dir(in);
+	yaffs_chunk_del(in->my_dev, in->hdr_chunk, 1, __LINE__);
+	in->hdr_chunk = 0;
+
+	yaffs_free_obj(in);
+	return YAFFS_OK;
+
+}
+
+static void yaffs_soft_del_file(struct yaffs_obj *obj)
+{
+	if (!obj->deleted ||
+	    obj->variant_type != YAFFS_OBJECT_TYPE_FILE ||
+	    obj->soft_del)
+		return;
+
+	if (obj->n_data_chunks <= 0) {
+		/* Empty file with no duplicate object headers,
+		 * just delete it immediately */
+		yaffs_free_tnode(obj->my_dev, obj->variant.file_variant.top);
+		obj->variant.file_variant.top = NULL;
+		yaffs_trace(YAFFS_TRACE_TRACING,
+			"yaffs: Deleting empty file %d",
+			obj->obj_id);
+		yaffs_generic_obj_del(obj);
+	} else {
+		yaffs_soft_del_worker(obj,
+				      obj->variant.file_variant.top,
+				      obj->variant.
+				      file_variant.top_level, 0);
+		obj->soft_del = 1;
+	}
+}
+
+/* Pruning removes any part of the file structure tree that is beyond the
+ * bounds of the file (ie that does not point to chunks).
+ *
+ * A file should only get pruned when its size is reduced.
+ *
+ * Before pruning, the chunks must be pulled from the tree and the
+ * level 0 tnode entries must be zeroed out.
+ * Could also use this for file deletion, but that's probably better handled
+ * by a special case.
+ *
+ * This function is recursive. For levels > 0 the function is called again on
+ * any sub-tree. For level == 0 we just check if the sub-tree has data.
+ * If there is no data in a subtree then it is pruned.
+ */
+
+static struct yaffs_tnode *yaffs_prune_worker(struct yaffs_dev *dev,
+					      struct yaffs_tnode *tn, u32 level,
+					      int del0)
+{
+	int i;
+	int has_data;
+
+	if (!tn)
+		return tn;
+
+	has_data = 0;
+
+	if (level > 0) {
+		for (i = 0; i < YAFFS_NTNODES_INTERNAL; i++) {
+			if (tn->internal[i]) {
+				tn->internal[i] =
+				    yaffs_prune_worker(dev,
+						tn->internal[i],
+						level - 1,
+						(i == 0) ? del0 : 1);
+			}
+
+			if (tn->internal[i])
+				has_data++;
+		}
+	} else {
+		int tnode_size_u32 = dev->tnode_size / sizeof(u32);
+		u32 *map = (u32 *) tn;
+
+		for (i = 0; !has_data && i < tnode_size_u32; i++) {
+			if (map[i])
+				has_data++;
+		}
+	}
+
+	if (has_data == 0 && del0) {
+		/* Free and return NULL */
+		yaffs_free_tnode(dev, tn);
+		tn = NULL;
+	}
+	return tn;
+}
+
+static int yaffs_prune_tree(struct yaffs_dev *dev,
+			    struct yaffs_file_var *file_struct)
+{
+	int i;
+	int has_data;
+	int done = 0;
+	struct yaffs_tnode *tn;
+
+	if (file_struct->top_level < 1)
+		return YAFFS_OK;
+
+	file_struct->top =
+	   yaffs_prune_worker(dev, file_struct->top, file_struct->top_level, 0);
+
+	/* Now we have a tree with all the non-zero branches NULL but
+	 * the height is the same as it was.
+	 * Let's see if we can trim internal tnodes to shorten the tree.
+	 * We can do this if only the 0th element in the tnode is in use
+	 * (ie all the non-zero are NULL)
+	 */
+
+	while (file_struct->top_level && !done) {
+		tn = file_struct->top;
+
+		has_data = 0;
+		for (i = 1; i < YAFFS_NTNODES_INTERNAL; i++) {
+			if (tn->internal[i])
+				has_data++;
+		}
+
+		if (!has_data) {
+			file_struct->top = tn->internal[0];
+			file_struct->top_level--;
+			yaffs_free_tnode(dev, tn);
+		} else {
+			done = 1;
+		}
+	}
+
+	return YAFFS_OK;
+}
+
+/*-------------------- End of File Structure functions.-------------------*/
+
+/* alloc_empty_obj gets us a clean Object.*/
+static struct yaffs_obj *yaffs_alloc_empty_obj(struct yaffs_dev *dev)
+{
+	struct yaffs_obj *obj = yaffs_alloc_raw_obj(dev);
+
+	if (!obj)
+		return obj;
+
+	dev->n_obj++;
+
+	/* Now sweeten it up... */
+
+	memset(obj, 0, sizeof(struct yaffs_obj));
+	obj->being_created = 1;
+
+	obj->my_dev = dev;
+	obj->hdr_chunk = 0;
+	obj->variant_type = YAFFS_OBJECT_TYPE_UNKNOWN;
+	INIT_LIST_HEAD(&(obj->hard_links));
+	INIT_LIST_HEAD(&(obj->hash_link));
+	INIT_LIST_HEAD(&obj->siblings);
+
+	/* Now make the directory sane */
+	if (dev->root_dir) {
+		obj->parent = dev->root_dir;
+		list_add(&(obj->siblings),
+			 &dev->root_dir->variant.dir_variant.children);
+	}
+
+	/* Add it to the lost and found directory.
+	 * NB Can't put root or lost-n-found in lost-n-found so
+	 * check if lost-n-found exists first
+	 */
+	if (dev->lost_n_found)
+		yaffs_add_obj_to_dir(dev->lost_n_found, obj);
+
+	obj->being_created = 0;
+
+	dev->checkpoint_blocks_required = 0;	/* force recalculation */
+
+	return obj;
+}
+
+static int yaffs_find_nice_bucket(struct yaffs_dev *dev)
+{
+	int i;
+	int l = 999;
+	int lowest = 999999;
+
+	/* Search for the shortest list or one that
+	 * isn't too long.
+	 */
+
+	for (i = 0; i < 10 && lowest > 4; i++) {
+		dev->bucket_finder++;
+		dev->bucket_finder %= YAFFS_NOBJECT_BUCKETS;
+		if (dev->obj_bucket[dev->bucket_finder].count < lowest) {
+			lowest = dev->obj_bucket[dev->bucket_finder].count;
+			l = dev->bucket_finder;
+		}
+	}
+
+	return l;
+}
+
+static int yaffs_new_obj_id(struct yaffs_dev *dev)
+{
+	int bucket = yaffs_find_nice_bucket(dev);
+	int found = 0;
+	struct list_head *i;
+	u32 n = (u32) bucket;
+
+	/* Now find an object value that has not already been taken
+	 * by scanning the list.
+	 */
+
+	while (!found) {
+		found = 1;
+		n += YAFFS_NOBJECT_BUCKETS;
+		if (1 || dev->obj_bucket[bucket].count > 0) {
+			list_for_each(i, &dev->obj_bucket[bucket].list) {
+				/* If there is already one in the list */
+				if (i && list_entry(i, struct yaffs_obj,
+						    hash_link)->obj_id == n) {
+					found = 0;
+				}
+			}
+		}
+	}
+	return n;
+}
+
+static void yaffs_hash_obj(struct yaffs_obj *in)
+{
+	int bucket = yaffs_hash_fn(in->obj_id);
+	struct yaffs_dev *dev = in->my_dev;
+
+	list_add(&in->hash_link, &dev->obj_bucket[bucket].list);
+	dev->obj_bucket[bucket].count++;
+}
+
+struct yaffs_obj *yaffs_find_by_number(struct yaffs_dev *dev, u32 number)
+{
+	int bucket = yaffs_hash_fn(number);
+	struct list_head *i;
+	struct yaffs_obj *in;
+
+	list_for_each(i, &dev->obj_bucket[bucket].list) {
+		/* Look if it is in the list */
+		in = list_entry(i, struct yaffs_obj, hash_link);
+		if (in->obj_id == number) {
+			/* Don't show if it is defered free */
+			if (in->defered_free)
+				return NULL;
+			return in;
+		}
+	}
+
+	return NULL;
+}
+
+static struct yaffs_obj *yaffs_new_obj(struct yaffs_dev *dev, int number,
+				enum yaffs_obj_type type)
+{
+	struct yaffs_obj *the_obj = NULL;
+	struct yaffs_tnode *tn = NULL;
+
+	if (number < 0)
+		number = yaffs_new_obj_id(dev);
+
+	if (type == YAFFS_OBJECT_TYPE_FILE) {
+		tn = yaffs_get_tnode(dev);
+		if (!tn)
+			return NULL;
+	}
+
+	the_obj = yaffs_alloc_empty_obj(dev);
+	if (!the_obj) {
+		if (tn)
+			yaffs_free_tnode(dev, tn);
+		return NULL;
+	}
+
+	the_obj->fake = 0;
+	the_obj->rename_allowed = 1;
+	the_obj->unlink_allowed = 1;
+	the_obj->obj_id = number;
+	yaffs_hash_obj(the_obj);
+	the_obj->variant_type = type;
+	yaffs_load_current_time(the_obj, 1, 1);
+
+	switch (type) {
+	case YAFFS_OBJECT_TYPE_FILE:
+		the_obj->variant.file_variant.file_size = 0;
+		the_obj->variant.file_variant.scanned_size = 0;
+		the_obj->variant.file_variant.shrink_size =
+						yaffs_max_file_size(dev);
+		the_obj->variant.file_variant.top_level = 0;
+		the_obj->variant.file_variant.top = tn;
+		break;
+	case YAFFS_OBJECT_TYPE_DIRECTORY:
+		INIT_LIST_HEAD(&the_obj->variant.dir_variant.children);
+		INIT_LIST_HEAD(&the_obj->variant.dir_variant.dirty);
+		break;
+	case YAFFS_OBJECT_TYPE_SYMLINK:
+	case YAFFS_OBJECT_TYPE_HARDLINK:
+	case YAFFS_OBJECT_TYPE_SPECIAL:
+		/* No action required */
+		break;
+	case YAFFS_OBJECT_TYPE_UNKNOWN:
+		/* todo this should not happen */
+		break;
+	}
+	return the_obj;
+}
+
+static struct yaffs_obj *yaffs_create_fake_dir(struct yaffs_dev *dev,
+					       int number, u32 mode)
+{
+
+	struct yaffs_obj *obj =
+	    yaffs_new_obj(dev, number, YAFFS_OBJECT_TYPE_DIRECTORY);
+
+	if (!obj)
+		return NULL;
+
+	obj->fake = 1;	/* it is fake so it might not use NAND */
+	obj->rename_allowed = 0;
+	obj->unlink_allowed = 0;
+	obj->deleted = 0;
+	obj->unlinked = 0;
+	obj->yst_mode = mode;
+	obj->my_dev = dev;
+	obj->hdr_chunk = 0;	/* Not a valid chunk. */
+	return obj;
+
+}
+
+
+static void yaffs_init_tnodes_and_objs(struct yaffs_dev *dev)
+{
+	int i;
+
+	dev->n_obj = 0;
+	dev->n_tnodes = 0;
+	yaffs_init_raw_tnodes_and_objs(dev);
+
+	for (i = 0; i < YAFFS_NOBJECT_BUCKETS; i++) {
+		INIT_LIST_HEAD(&dev->obj_bucket[i].list);
+		dev->obj_bucket[i].count = 0;
+	}
+}
+
+struct yaffs_obj *yaffs_find_or_create_by_number(struct yaffs_dev *dev,
+						 int number,
+						 enum yaffs_obj_type type)
+{
+	struct yaffs_obj *the_obj = NULL;
+
+	if (number > 0)
+		the_obj = yaffs_find_by_number(dev, number);
+
+	if (!the_obj)
+		the_obj = yaffs_new_obj(dev, number, type);
+
+	return the_obj;
+
+}
+
+YCHAR *yaffs_clone_str(const YCHAR *str)
+{
+	YCHAR *new_str = NULL;
+	int len;
+
+	if (!str)
+		str = _Y("");
+
+	len = strnlen(str, YAFFS_MAX_ALIAS_LENGTH);
+	new_str = kmalloc((len + 1) * sizeof(YCHAR), GFP_NOFS);
+	if (new_str) {
+		strncpy(new_str, str, len);
+		new_str[len] = 0;
+	}
+	return new_str;
+
+}
+/*
+ *yaffs_update_parent() handles fixing a directories mtime and ctime when a new
+ * link (ie. name) is created or deleted in the directory.
+ *
+ * ie.
+ *   create dir/a : update dir's mtime/ctime
+ *   rm dir/a:   update dir's mtime/ctime
+ *   modify dir/a: don't update dir's mtimme/ctime
+ *
+ * This can be handled immediately or defered. Defering helps reduce the number
+ * of updates when many files in a directory are changed within a brief period.
+ *
+ * If the directory updating is defered then yaffs_update_dirty_dirs must be
+ * called periodically.
+ */
+
+static void yaffs_update_parent(struct yaffs_obj *obj)
+{
+	struct yaffs_dev *dev;
+
+	if (!obj)
+		return;
+	dev = obj->my_dev;
+	obj->dirty = 1;
+	yaffs_load_current_time(obj, 0, 1);
+	if (dev->param.defered_dir_update) {
+		struct list_head *link = &obj->variant.dir_variant.dirty;
+
+		if (list_empty(link)) {
+			list_add(link, &dev->dirty_dirs);
+			yaffs_trace(YAFFS_TRACE_BACKGROUND,
+			  "Added object %d to dirty directories",
+			   obj->obj_id);
+		}
+
+	} else {
+		yaffs_update_oh(obj, NULL, 0, 0, 0, NULL);
+	}
+}
+
+void yaffs_update_dirty_dirs(struct yaffs_dev *dev)
+{
+	struct list_head *link;
+	struct yaffs_obj *obj;
+	struct yaffs_dir_var *d_s;
+	union yaffs_obj_var *o_v;
+
+	yaffs_trace(YAFFS_TRACE_BACKGROUND, "Update dirty directories");
+
+	while (!list_empty(&dev->dirty_dirs)) {
+		link = dev->dirty_dirs.next;
+		list_del_init(link);
+
+		d_s = list_entry(link, struct yaffs_dir_var, dirty);
+		o_v = list_entry(d_s, union yaffs_obj_var, dir_variant);
+		obj = list_entry(o_v, struct yaffs_obj, variant);
+
+		yaffs_trace(YAFFS_TRACE_BACKGROUND, "Update directory %d",
+			obj->obj_id);
+
+		if (obj->dirty)
+			yaffs_update_oh(obj, NULL, 0, 0, 0, NULL);
+	}
+}
+
+/*
+ * Mknod (create) a new object.
+ * equiv_obj only has meaning for a hard link;
+ * alias_str only has meaning for a symlink.
+ * rdev only has meaning for devices (a subset of special objects)
+ */
+
+static struct yaffs_obj *yaffs_create_obj(enum yaffs_obj_type type,
+					  struct yaffs_obj *parent,
+					  const YCHAR *name,
+					  u32 mode,
+					  u32 uid,
+					  u32 gid,
+					  struct yaffs_obj *equiv_obj,
+					  const YCHAR *alias_str, u32 rdev)
+{
+	struct yaffs_obj *in;
+	YCHAR *str = NULL;
+	struct yaffs_dev *dev = parent->my_dev;
+
+	/* Check if the entry exists.
+	 * If it does then fail the call since we don't want a dup. */
+	if (yaffs_find_by_name(parent, name))
+		return NULL;
+
+	if (type == YAFFS_OBJECT_TYPE_SYMLINK) {
+		str = yaffs_clone_str(alias_str);
+		if (!str)
+			return NULL;
+	}
+
+	in = yaffs_new_obj(dev, -1, type);
+
+	if (!in) {
+		kfree(str);
+		return NULL;
+	}
+
+	in->hdr_chunk = 0;
+	in->valid = 1;
+	in->variant_type = type;
+
+	in->yst_mode = mode;
+
+	yaffs_attribs_init(in, gid, uid, rdev);
+
+	in->n_data_chunks = 0;
+
+	yaffs_set_obj_name(in, name);
+	in->dirty = 1;
+
+	yaffs_add_obj_to_dir(parent, in);
+
+	in->my_dev = parent->my_dev;
+
+	switch (type) {
+	case YAFFS_OBJECT_TYPE_SYMLINK:
+		in->variant.symlink_variant.alias = str;
+		break;
+	case YAFFS_OBJECT_TYPE_HARDLINK:
+		in->variant.hardlink_variant.equiv_obj = equiv_obj;
+		in->variant.hardlink_variant.equiv_id = equiv_obj->obj_id;
+		list_add(&in->hard_links, &equiv_obj->hard_links);
+		break;
+	case YAFFS_OBJECT_TYPE_FILE:
+	case YAFFS_OBJECT_TYPE_DIRECTORY:
+	case YAFFS_OBJECT_TYPE_SPECIAL:
+	case YAFFS_OBJECT_TYPE_UNKNOWN:
+		/* do nothing */
+		break;
+	}
+
+	if (yaffs_update_oh(in, name, 0, 0, 0, NULL) < 0) {
+		/* Could not create the object header, fail */
+		yaffs_del_obj(in);
+		in = NULL;
+	}
+
+	if (in)
+		yaffs_update_parent(parent);
+
+	return in;
+}
+
+struct yaffs_obj *yaffs_create_file(struct yaffs_obj *parent,
+				    const YCHAR *name, u32 mode, u32 uid,
+				    u32 gid)
+{
+	return yaffs_create_obj(YAFFS_OBJECT_TYPE_FILE, parent, name, mode,
+				uid, gid, NULL, NULL, 0);
+}
+
+struct yaffs_obj *yaffs_create_dir(struct yaffs_obj *parent, const YCHAR *name,
+				   u32 mode, u32 uid, u32 gid)
+{
+	return yaffs_create_obj(YAFFS_OBJECT_TYPE_DIRECTORY, parent, name,
+				mode, uid, gid, NULL, NULL, 0);
+}
+
+struct yaffs_obj *yaffs_create_special(struct yaffs_obj *parent,
+				       const YCHAR *name, u32 mode, u32 uid,
+				       u32 gid, u32 rdev)
+{
+	return yaffs_create_obj(YAFFS_OBJECT_TYPE_SPECIAL, parent, name, mode,
+				uid, gid, NULL, NULL, rdev);
+}
+
+struct yaffs_obj *yaffs_create_symlink(struct yaffs_obj *parent,
+				       const YCHAR *name, u32 mode, u32 uid,
+				       u32 gid, const YCHAR *alias)
+{
+	return yaffs_create_obj(YAFFS_OBJECT_TYPE_SYMLINK, parent, name, mode,
+				uid, gid, NULL, alias, 0);
+}
+
+/* yaffs_link_obj returns the object id of the equivalent object.*/
+struct yaffs_obj *yaffs_link_obj(struct yaffs_obj *parent, const YCHAR * name,
+				 struct yaffs_obj *equiv_obj)
+{
+	/* Get the real object in case we were fed a hard link obj */
+	equiv_obj = yaffs_get_equivalent_obj(equiv_obj);
+
+	if (yaffs_create_obj(YAFFS_OBJECT_TYPE_HARDLINK,
+			parent, name, 0, 0, 0,
+			equiv_obj, NULL, 0))
+		return equiv_obj;
+
+	return NULL;
+
+}
+
+
+
+/*---------------------- Block Management and Page Allocation -------------*/
+
+static void yaffs_deinit_blocks(struct yaffs_dev *dev)
+{
+	if (dev->block_info_alt && dev->block_info)
+		vfree(dev->block_info);
+	else
+		kfree(dev->block_info);
+
+	dev->block_info_alt = 0;
+
+	dev->block_info = NULL;
+
+	if (dev->chunk_bits_alt && dev->chunk_bits)
+		vfree(dev->chunk_bits);
+	else
+		kfree(dev->chunk_bits);
+	dev->chunk_bits_alt = 0;
+	dev->chunk_bits = NULL;
+}
+
+static int yaffs_init_blocks(struct yaffs_dev *dev)
+{
+	int n_blocks = dev->internal_end_block - dev->internal_start_block + 1;
+
+	dev->block_info = NULL;
+	dev->chunk_bits = NULL;
+	dev->alloc_block = -1;	/* force it to get a new one */
+
+	/* If the first allocation strategy fails, thry the alternate one */
+	dev->block_info =
+		kmalloc(n_blocks * sizeof(struct yaffs_block_info), GFP_NOFS);
+	if (!dev->block_info) {
+		dev->block_info =
+		    vmalloc(n_blocks * sizeof(struct yaffs_block_info));
+		dev->block_info_alt = 1;
+	} else {
+		dev->block_info_alt = 0;
+	}
+
+	if (!dev->block_info)
+		goto alloc_error;
+
+	/* Set up dynamic blockinfo stuff. Round up bytes. */
+	dev->chunk_bit_stride = (dev->param.chunks_per_block + 7) / 8;
+	dev->chunk_bits =
+		kmalloc(dev->chunk_bit_stride * n_blocks, GFP_NOFS);
+	if (!dev->chunk_bits) {
+		dev->chunk_bits =
+		    vmalloc(dev->chunk_bit_stride * n_blocks);
+		dev->chunk_bits_alt = 1;
+	} else {
+		dev->chunk_bits_alt = 0;
+	}
+	if (!dev->chunk_bits)
+		goto alloc_error;
+
+
+	memset(dev->block_info, 0, n_blocks * sizeof(struct yaffs_block_info));
+	memset(dev->chunk_bits, 0, dev->chunk_bit_stride * n_blocks);
+	return YAFFS_OK;
+
+alloc_error:
+	yaffs_deinit_blocks(dev);
+	return YAFFS_FAIL;
+}
+
+
+void yaffs_block_became_dirty(struct yaffs_dev *dev, int block_no)
+{
+	struct yaffs_block_info *bi = yaffs_get_block_info(dev, block_no);
+	int erased_ok = 0;
+	int i;
+
+	/* If the block is still healthy erase it and mark as clean.
+	 * If the block has had a data failure, then retire it.
+	 */
+
+	yaffs_trace(YAFFS_TRACE_GC | YAFFS_TRACE_ERASE,
+		"yaffs_block_became_dirty block %d state %d %s",
+		block_no, bi->block_state,
+		(bi->needs_retiring) ? "needs retiring" : "");
+
+	yaffs2_clear_oldest_dirty_seq(dev, bi);
+
+	bi->block_state = YAFFS_BLOCK_STATE_DIRTY;
+
+	/* If this is the block being garbage collected then stop gc'ing */
+	if (block_no == dev->gc_block)
+		dev->gc_block = 0;
+
+	/* If this block is currently the best candidate for gc
+	 * then drop as a candidate */
+	if (block_no == dev->gc_dirtiest) {
+		dev->gc_dirtiest = 0;
+		dev->gc_pages_in_use = 0;
+	}
+
+	if (!bi->needs_retiring) {
+		yaffs2_checkpt_invalidate(dev);
+		erased_ok = yaffs_erase_block(dev, block_no);
+		if (!erased_ok) {
+			dev->n_erase_failures++;
+			yaffs_trace(YAFFS_TRACE_ERROR | YAFFS_TRACE_BAD_BLOCKS,
+			  "**>> Erasure failed %d", block_no);
+		}
+	}
+
+	/* Verify erasure if needed */
+	if (erased_ok &&
+	    ((yaffs_trace_mask & YAFFS_TRACE_ERASE) ||
+	     !yaffs_skip_verification(dev))) {
+		for (i = 0; i < dev->param.chunks_per_block; i++) {
+			if (!yaffs_check_chunk_erased(dev,
+				block_no * dev->param.chunks_per_block + i)) {
+				yaffs_trace(YAFFS_TRACE_ERROR,
+					">>Block %d erasure supposedly OK, but chunk %d not erased",
+					block_no, i);
+			}
+		}
+	}
+
+	if (!erased_ok) {
+		/* We lost a block of free space */
+		dev->n_free_chunks -= dev->param.chunks_per_block;
+		yaffs_retire_block(dev, block_no);
+		yaffs_trace(YAFFS_TRACE_ERROR | YAFFS_TRACE_BAD_BLOCKS,
+			"**>> Block %d retired", block_no);
+		return;
+	}
+
+	/* Clean it up... */
+	bi->block_state = YAFFS_BLOCK_STATE_EMPTY;
+	bi->seq_number = 0;
+	dev->n_erased_blocks++;
+	bi->pages_in_use = 0;
+	bi->soft_del_pages = 0;
+	bi->has_shrink_hdr = 0;
+	bi->skip_erased_check = 1;	/* Clean, so no need to check */
+	bi->gc_prioritise = 0;
+	bi->has_summary = 0;
+
+	yaffs_clear_chunk_bits(dev, block_no);
+
+	yaffs_trace(YAFFS_TRACE_ERASE, "Erased block %d", block_no);
+}
+
+static inline int yaffs_gc_process_chunk(struct yaffs_dev *dev,
+					struct yaffs_block_info *bi,
+					int old_chunk, u8 *buffer)
+{
+	int new_chunk;
+	int mark_flash = 1;
+	struct yaffs_ext_tags tags;
+	struct yaffs_obj *object;
+	int matching_chunk;
+	int ret_val = YAFFS_OK;
+
+	memset(&tags, 0, sizeof(tags));
+	yaffs_rd_chunk_tags_nand(dev, old_chunk,
+				 buffer, &tags);
+	object = yaffs_find_by_number(dev, tags.obj_id);
+
+	yaffs_trace(YAFFS_TRACE_GC_DETAIL,
+		"Collecting chunk in block %d, %d %d %d ",
+		dev->gc_chunk, tags.obj_id,
+		tags.chunk_id, tags.n_bytes);
+
+	if (object && !yaffs_skip_verification(dev)) {
+		if (tags.chunk_id == 0)
+			matching_chunk =
+			    object->hdr_chunk;
+		else if (object->soft_del)
+			/* Defeat the test */
+			matching_chunk = old_chunk;
+		else
+			matching_chunk =
+			    yaffs_find_chunk_in_file
+			    (object, tags.chunk_id,
+			     NULL);
+
+		if (old_chunk != matching_chunk)
+			yaffs_trace(YAFFS_TRACE_ERROR,
+				"gc: page in gc mismatch: %d %d %d %d",
+				old_chunk,
+				matching_chunk,
+				tags.obj_id,
+				tags.chunk_id);
+	}
+
+	if (!object) {
+		yaffs_trace(YAFFS_TRACE_ERROR,
+			"page %d in gc has no object: %d %d %d ",
+			old_chunk,
+			tags.obj_id, tags.chunk_id,
+			tags.n_bytes);
+	}
+
+	if (object &&
+	    object->deleted &&
+	    object->soft_del && tags.chunk_id != 0) {
+		/* Data chunk in a soft deleted file,
+		 * throw it away.
+		 * It's a soft deleted data chunk,
+		 * No need to copy this, just forget
+		 * about it and fix up the object.
+		 */
+
+		/* Free chunks already includes
+		 * softdeleted chunks, how ever this
+		 * chunk is going to soon be really
+		 * deleted which will increment free
+		 * chunks. We have to decrement free
+		 * chunks so this works out properly.
+		 */
+		dev->n_free_chunks--;
+		bi->soft_del_pages--;
+
+		object->n_data_chunks--;
+		if (object->n_data_chunks <= 0) {
+			/* remeber to clean up obj */
+			dev->gc_cleanup_list[dev->n_clean_ups] = tags.obj_id;
+			dev->n_clean_ups++;
+		}
+		mark_flash = 0;
+	} else if (object) {
+		/* It's either a data chunk in a live
+		 * file or an ObjectHeader, so we're
+		 * interested in it.
+		 * NB Need to keep the ObjectHeaders of
+		 * deleted files until the whole file
+		 * has been deleted off
+		 */
+		tags.serial_number++;
+		dev->n_gc_copies++;
+
+		if (tags.chunk_id == 0) {
+			/* It is an object Id,
+			 * We need to nuke the
+			 * shrinkheader flags since its
+			 * work is done.
+			 * Also need to clean up
+			 * shadowing.
+			 */
+			struct yaffs_obj_hdr *oh;
+			oh = (struct yaffs_obj_hdr *) buffer;
+
+			oh->is_shrink = 0;
+			tags.extra_is_shrink = 0;
+			oh->shadows_obj = 0;
+			oh->inband_shadowed_obj_id = 0;
+			tags.extra_shadows = 0;
+
+			/* Update file size */
+			if (object->variant_type == YAFFS_OBJECT_TYPE_FILE) {
+				yaffs_oh_size_load(oh,
+				    object->variant.file_variant.file_size);
+				tags.extra_file_size =
+				    object->variant.file_variant.file_size;
+			}
+
+			yaffs_verify_oh(object, oh, &tags, 1);
+			new_chunk =
+			    yaffs_write_new_chunk(dev, (u8 *) oh, &tags, 1);
+		} else {
+			new_chunk =
+			    yaffs_write_new_chunk(dev, buffer, &tags, 1);
+		}
+
+		if (new_chunk < 0) {
+			ret_val = YAFFS_FAIL;
+		} else {
+
+			/* Now fix up the Tnodes etc. */
+
+			if (tags.chunk_id == 0) {
+				/* It's a header */
+				object->hdr_chunk = new_chunk;
+				object->serial = tags.serial_number;
+			} else {
+				/* It's a data chunk */
+				yaffs_put_chunk_in_file(object, tags.chunk_id,
+							new_chunk, 0);
+			}
+		}
+	}
+	if (ret_val == YAFFS_OK)
+		yaffs_chunk_del(dev, old_chunk, mark_flash, __LINE__);
+	return ret_val;
+}
+
+static int yaffs_gc_block(struct yaffs_dev *dev, int block, int whole_block)
+{
+	int old_chunk;
+	int ret_val = YAFFS_OK;
+	int i;
+	int is_checkpt_block;
+	int max_copies;
+	int chunks_before = yaffs_get_erased_chunks(dev);
+	int chunks_after;
+	struct yaffs_block_info *bi = yaffs_get_block_info(dev, block);
+
+	is_checkpt_block = (bi->block_state == YAFFS_BLOCK_STATE_CHECKPOINT);
+
+	yaffs_trace(YAFFS_TRACE_TRACING,
+		"Collecting block %d, in use %d, shrink %d, whole_block %d",
+		block, bi->pages_in_use, bi->has_shrink_hdr,
+		whole_block);
+
+	/*yaffs_verify_free_chunks(dev); */
+
+	if (bi->block_state == YAFFS_BLOCK_STATE_FULL)
+		bi->block_state = YAFFS_BLOCK_STATE_COLLECTING;
+
+	bi->has_shrink_hdr = 0;	/* clear the flag so that the block can erase */
+
+	dev->gc_disable = 1;
+
+	yaffs_summary_gc(dev, block);
+
+	if (is_checkpt_block || !yaffs_still_some_chunks(dev, block)) {
+		yaffs_trace(YAFFS_TRACE_TRACING,
+			"Collecting block %d that has no chunks in use",
+			block);
+		yaffs_block_became_dirty(dev, block);
+	} else {
+
+		u8 *buffer = yaffs_get_temp_buffer(dev);
+
+		yaffs_verify_blk(dev, bi, block);
+
+		max_copies = (whole_block) ? dev->param.chunks_per_block : 5;
+		old_chunk = block * dev->param.chunks_per_block + dev->gc_chunk;
+
+		for (/* init already done */ ;
+		     ret_val == YAFFS_OK &&
+		     dev->gc_chunk < dev->param.chunks_per_block &&
+		     (bi->block_state == YAFFS_BLOCK_STATE_COLLECTING) &&
+		     max_copies > 0;
+		     dev->gc_chunk++, old_chunk++) {
+			if (yaffs_check_chunk_bit(dev, block, dev->gc_chunk)) {
+				/* Page is in use and might need to be copied */
+				max_copies--;
+				ret_val = yaffs_gc_process_chunk(dev, bi,
+							old_chunk, buffer);
+			}
+		}
+		yaffs_release_temp_buffer(dev, buffer);
+	}
+
+	yaffs_verify_collected_blk(dev, bi, block);
+
+	if (bi->block_state == YAFFS_BLOCK_STATE_COLLECTING) {
+		/*
+		 * The gc did not complete. Set block state back to FULL
+		 * because checkpointing does not restore gc.
+		 */
+		bi->block_state = YAFFS_BLOCK_STATE_FULL;
+	} else {
+		/* The gc completed. */
+		/* Do any required cleanups */
+		for (i = 0; i < dev->n_clean_ups; i++) {
+			/* Time to delete the file too */
+			struct yaffs_obj *object =
+			    yaffs_find_by_number(dev, dev->gc_cleanup_list[i]);
+			if (object) {
+				yaffs_free_tnode(dev,
+					  object->variant.file_variant.top);
+				object->variant.file_variant.top = NULL;
+				yaffs_trace(YAFFS_TRACE_GC,
+					"yaffs: About to finally delete object %d",
+					object->obj_id);
+				yaffs_generic_obj_del(object);
+				object->my_dev->n_deleted_files--;
+			}
+
+		}
+		chunks_after = yaffs_get_erased_chunks(dev);
+		if (chunks_before >= chunks_after)
+			yaffs_trace(YAFFS_TRACE_GC,
+				"gc did not increase free chunks before %d after %d",
+				chunks_before, chunks_after);
+		dev->gc_block = 0;
+		dev->gc_chunk = 0;
+		dev->n_clean_ups = 0;
+	}
+
+	dev->gc_disable = 0;
+
+	return ret_val;
+}
+
+/*
+ * find_gc_block() selects the dirtiest block (or close enough)
+ * for garbage collection.
+ */
+
+static unsigned yaffs_find_gc_block(struct yaffs_dev *dev,
+				    int aggressive, int background)
+{
+	int i;
+	int iterations;
+	unsigned selected = 0;
+	int prioritised = 0;
+	int prioritised_exist = 0;
+	struct yaffs_block_info *bi;
+	int threshold;
+
+	/* First let's see if we need to grab a prioritised block */
+	if (dev->has_pending_prioritised_gc && !aggressive) {
+		dev->gc_dirtiest = 0;
+		bi = dev->block_info;
+		for (i = dev->internal_start_block;
+		     i <= dev->internal_end_block && !selected; i++) {
+
+			if (bi->gc_prioritise) {
+				prioritised_exist = 1;
+				if (bi->block_state == YAFFS_BLOCK_STATE_FULL &&
+				    yaffs_block_ok_for_gc(dev, bi)) {
+					selected = i;
+					prioritised = 1;
+				}
+			}
+			bi++;
+		}
+
+		/*
+		 * If there is a prioritised block and none was selected then
+		 * this happened because there is at least one old dirty block
+		 * gumming up the works. Let's gc the oldest dirty block.
+		 */
+
+		if (prioritised_exist &&
+		    !selected && dev->oldest_dirty_block > 0)
+			selected = dev->oldest_dirty_block;
+
+		if (!prioritised_exist)	/* None found, so we can clear this */
+			dev->has_pending_prioritised_gc = 0;
+	}
+
+	/* If we're doing aggressive GC then we are happy to take a less-dirty
+	 * block, and search harder.
+	 * else (leasurely gc), then we only bother to do this if the
+	 * block has only a few pages in use.
+	 */
+
+	if (!selected) {
+		int pages_used;
+		int n_blocks =
+		    dev->internal_end_block - dev->internal_start_block + 1;
+		if (aggressive) {
+			threshold = dev->param.chunks_per_block;
+			iterations = n_blocks;
+		} else {
+			int max_threshold;
+
+			if (background)
+				max_threshold = dev->param.chunks_per_block / 2;
+			else
+				max_threshold = dev->param.chunks_per_block / 8;
+
+			if (max_threshold < YAFFS_GC_PASSIVE_THRESHOLD)
+				max_threshold = YAFFS_GC_PASSIVE_THRESHOLD;
+
+			threshold = background ? (dev->gc_not_done + 2) * 2 : 0;
+			if (threshold < YAFFS_GC_PASSIVE_THRESHOLD)
+				threshold = YAFFS_GC_PASSIVE_THRESHOLD;
+			if (threshold > max_threshold)
+				threshold = max_threshold;
+
+			iterations = n_blocks / 16 + 1;
+			if (iterations > 100)
+				iterations = 100;
+		}
+
+		for (i = 0;
+		     i < iterations &&
+		     (dev->gc_dirtiest < 1 ||
+		      dev->gc_pages_in_use > YAFFS_GC_GOOD_ENOUGH);
+		     i++) {
+			dev->gc_block_finder++;
+			if (dev->gc_block_finder < dev->internal_start_block ||
+			    dev->gc_block_finder > dev->internal_end_block)
+				dev->gc_block_finder =
+				    dev->internal_start_block;
+
+			bi = yaffs_get_block_info(dev, dev->gc_block_finder);
+
+			pages_used = bi->pages_in_use - bi->soft_del_pages;
+
+			if (bi->block_state == YAFFS_BLOCK_STATE_FULL &&
+			    pages_used < dev->param.chunks_per_block &&
+			    (dev->gc_dirtiest < 1 ||
+			     pages_used < dev->gc_pages_in_use) &&
+			    yaffs_block_ok_for_gc(dev, bi)) {
+				dev->gc_dirtiest = dev->gc_block_finder;
+				dev->gc_pages_in_use = pages_used;
+			}
+		}
+
+		if (dev->gc_dirtiest > 0 && dev->gc_pages_in_use <= threshold)
+			selected = dev->gc_dirtiest;
+	}
+
+	/*
+	 * If nothing has been selected for a while, try the oldest dirty
+	 * because that's gumming up the works.
+	 */
+
+	if (!selected && dev->param.is_yaffs2 &&
+	    dev->gc_not_done >= (background ? 10 : 20)) {
+		yaffs2_find_oldest_dirty_seq(dev);
+		if (dev->oldest_dirty_block > 0) {
+			selected = dev->oldest_dirty_block;
+			dev->gc_dirtiest = selected;
+			dev->oldest_dirty_gc_count++;
+			bi = yaffs_get_block_info(dev, selected);
+			dev->gc_pages_in_use =
+			    bi->pages_in_use - bi->soft_del_pages;
+		} else {
+			dev->gc_not_done = 0;
+		}
+	}
+
+	if (selected) {
+		yaffs_trace(YAFFS_TRACE_GC,
+			"GC Selected block %d with %d free, prioritised:%d",
+			selected,
+			dev->param.chunks_per_block - dev->gc_pages_in_use,
+			prioritised);
+
+		dev->n_gc_blocks++;
+		if (background)
+			dev->bg_gcs++;
+
+		dev->gc_dirtiest = 0;
+		dev->gc_pages_in_use = 0;
+		dev->gc_not_done = 0;
+		if (dev->refresh_skip > 0)
+			dev->refresh_skip--;
+	} else {
+		dev->gc_not_done++;
+		yaffs_trace(YAFFS_TRACE_GC,
+			"GC none: finder %d skip %d threshold %d dirtiest %d using %d oldest %d%s",
+			dev->gc_block_finder, dev->gc_not_done, threshold,
+			dev->gc_dirtiest, dev->gc_pages_in_use,
+			dev->oldest_dirty_block, background ? " bg" : "");
+	}
+
+	return selected;
+}
+
+/* New garbage collector
+ * If we're very low on erased blocks then we do aggressive garbage collection
+ * otherwise we do "leasurely" garbage collection.
+ * Aggressive gc looks further (whole array) and will accept less dirty blocks.
+ * Passive gc only inspects smaller areas and only accepts more dirty blocks.
+ *
+ * The idea is to help clear out space in a more spread-out manner.
+ * Dunno if it really does anything useful.
+ */
+static int yaffs_check_gc(struct yaffs_dev *dev, int background)
+{
+	int aggressive = 0;
+	int gc_ok = YAFFS_OK;
+	int max_tries = 0;
+	int min_erased;
+	int erased_chunks;
+	int checkpt_block_adjust;
+
+	if (dev->param.gc_control && (dev->param.gc_control(dev) & 1) == 0)
+		return YAFFS_OK;
+
+	if (dev->gc_disable)
+		/* Bail out so we don't get recursive gc */
+		return YAFFS_OK;
+
+	/* This loop should pass the first time.
+	 * Only loops here if the collection does not increase space.
+	 */
+
+	do {
+		max_tries++;
+
+		checkpt_block_adjust = yaffs_calc_checkpt_blocks_required(dev);
+
+		min_erased =
+		    dev->param.n_reserved_blocks + checkpt_block_adjust + 1;
+		erased_chunks =
+		    dev->n_erased_blocks * dev->param.chunks_per_block;
+
+		/* If we need a block soon then do aggressive gc. */
+		if (dev->n_erased_blocks < min_erased)
+			aggressive = 1;
+		else {
+			if (!background
+			    && erased_chunks > (dev->n_free_chunks / 4))
+				break;
+
+			if (dev->gc_skip > 20)
+				dev->gc_skip = 20;
+			if (erased_chunks < dev->n_free_chunks / 2 ||
+			    dev->gc_skip < 1 || background)
+				aggressive = 0;
+			else {
+				dev->gc_skip--;
+				break;
+			}
+		}
+
+		dev->gc_skip = 5;
+
+		/* If we don't already have a block being gc'd then see if we
+		 * should start another */
+
+		if (dev->gc_block < 1 && !aggressive) {
+			dev->gc_block = yaffs2_find_refresh_block(dev);
+			dev->gc_chunk = 0;
+			dev->n_clean_ups = 0;
+		}
+		if (dev->gc_block < 1) {
+			dev->gc_block =
+			    yaffs_find_gc_block(dev, aggressive, background);
+			dev->gc_chunk = 0;
+			dev->n_clean_ups = 0;
+		}
+
+		if (dev->gc_block > 0) {
+			dev->all_gcs++;
+			if (!aggressive)
+				dev->passive_gc_count++;
+
+			yaffs_trace(YAFFS_TRACE_GC,
+				"yaffs: GC n_erased_blocks %d aggressive %d",
+				dev->n_erased_blocks, aggressive);
+
+			gc_ok = yaffs_gc_block(dev, dev->gc_block, aggressive);
+		}
+
+		if (dev->n_erased_blocks < (dev->param.n_reserved_blocks) &&
+		    dev->gc_block > 0) {
+			yaffs_trace(YAFFS_TRACE_GC,
+				"yaffs: GC !!!no reclaim!!! n_erased_blocks %d after try %d block %d",
+				dev->n_erased_blocks, max_tries,
+				dev->gc_block);
+		}
+	} while ((dev->n_erased_blocks < dev->param.n_reserved_blocks) &&
+		 (dev->gc_block > 0) && (max_tries < 2));
+
+	return aggressive ? gc_ok : YAFFS_OK;
+}
+
+/*
+ * yaffs_bg_gc()
+ * Garbage collects. Intended to be called from a background thread.
+ * Returns non-zero if at least half the free chunks are erased.
+ */
+int yaffs_bg_gc(struct yaffs_dev *dev, unsigned urgency)
+{
+	int erased_chunks = dev->n_erased_blocks * dev->param.chunks_per_block;
+
+	yaffs_trace(YAFFS_TRACE_BACKGROUND, "Background gc %u", urgency);
+
+	yaffs_check_gc(dev, 1);
+	return erased_chunks > dev->n_free_chunks / 2;
+}
+
+/*-------------------- Data file manipulation -----------------*/
+
+static int yaffs_rd_data_obj(struct yaffs_obj *in, int inode_chunk, u8 * buffer)
+{
+	int nand_chunk = yaffs_find_chunk_in_file(in, inode_chunk, NULL);
+
+	if (nand_chunk >= 0)
+		return yaffs_rd_chunk_tags_nand(in->my_dev, nand_chunk,
+						buffer, NULL);
+	else {
+		yaffs_trace(YAFFS_TRACE_NANDACCESS,
+			"Chunk %d not found zero instead",
+			nand_chunk);
+		/* get sane (zero) data if you read a hole */
+		memset(buffer, 0, in->my_dev->data_bytes_per_chunk);
+		return 0;
+	}
+
+}
+
+void yaffs_chunk_del(struct yaffs_dev *dev, int chunk_id, int mark_flash,
+		     int lyn)
+{
+	int block;
+	int page;
+	struct yaffs_ext_tags tags;
+	struct yaffs_block_info *bi;
+
+	if (chunk_id <= 0)
+		return;
+
+	dev->n_deletions++;
+	block = chunk_id / dev->param.chunks_per_block;
+	page = chunk_id % dev->param.chunks_per_block;
+
+	if (!yaffs_check_chunk_bit(dev, block, page))
+		yaffs_trace(YAFFS_TRACE_VERIFY,
+			"Deleting invalid chunk %d", chunk_id);
+
+	bi = yaffs_get_block_info(dev, block);
+
+	yaffs2_update_oldest_dirty_seq(dev, block, bi);
+
+	yaffs_trace(YAFFS_TRACE_DELETION,
+		"line %d delete of chunk %d",
+		lyn, chunk_id);
+
+	if (!dev->param.is_yaffs2 && mark_flash &&
+	    bi->block_state != YAFFS_BLOCK_STATE_COLLECTING) {
+
+		memset(&tags, 0, sizeof(tags));
+		tags.is_deleted = 1;
+		yaffs_wr_chunk_tags_nand(dev, chunk_id, NULL, &tags);
+		yaffs_handle_chunk_update(dev, chunk_id, &tags);
+	} else {
+		dev->n_unmarked_deletions++;
+	}
+
+	/* Pull out of the management area.
+	 * If the whole block became dirty, this will kick off an erasure.
+	 */
+	if (bi->block_state == YAFFS_BLOCK_STATE_ALLOCATING ||
+	    bi->block_state == YAFFS_BLOCK_STATE_FULL ||
+	    bi->block_state == YAFFS_BLOCK_STATE_NEEDS_SCAN ||
+	    bi->block_state == YAFFS_BLOCK_STATE_COLLECTING) {
+		dev->n_free_chunks++;
+		yaffs_clear_chunk_bit(dev, block, page);
+		bi->pages_in_use--;
+
+		if (bi->pages_in_use == 0 &&
+		    !bi->has_shrink_hdr &&
+		    bi->block_state != YAFFS_BLOCK_STATE_ALLOCATING &&
+		    bi->block_state != YAFFS_BLOCK_STATE_NEEDS_SCAN) {
+			yaffs_block_became_dirty(dev, block);
+		}
+	}
+}
+
+static int yaffs_wr_data_obj(struct yaffs_obj *in, int inode_chunk,
+			     const u8 *buffer, int n_bytes, int use_reserve)
+{
+	/* Find old chunk Need to do this to get serial number
+	 * Write new one and patch into tree.
+	 * Invalidate old tags.
+	 */
+
+	int prev_chunk_id;
+	struct yaffs_ext_tags prev_tags;
+	int new_chunk_id;
+	struct yaffs_ext_tags new_tags;
+	struct yaffs_dev *dev = in->my_dev;
+
+	yaffs_check_gc(dev, 0);
+
+	/* Get the previous chunk at this location in the file if it exists.
+	 * If it does not exist then put a zero into the tree. This creates
+	 * the tnode now, rather than later when it is harder to clean up.
+	 */
+	prev_chunk_id = yaffs_find_chunk_in_file(in, inode_chunk, &prev_tags);
+	if (prev_chunk_id < 1 &&
+	    !yaffs_put_chunk_in_file(in, inode_chunk, 0, 0))
+		return 0;
+
+	/* Set up new tags */
+	memset(&new_tags, 0, sizeof(new_tags));
+
+	new_tags.chunk_id = inode_chunk;
+	new_tags.obj_id = in->obj_id;
+	new_tags.serial_number =
+	    (prev_chunk_id > 0) ? prev_tags.serial_number + 1 : 1;
+	new_tags.n_bytes = n_bytes;
+
+	if (n_bytes < 1 || n_bytes > dev->param.total_bytes_per_chunk) {
+		yaffs_trace(YAFFS_TRACE_ERROR,
+		  "Writing %d bytes to chunk!!!!!!!!!",
+		   n_bytes);
+		BUG();
+	}
+
+	new_chunk_id =
+	    yaffs_write_new_chunk(dev, buffer, &new_tags, use_reserve);
+
+	if (new_chunk_id > 0) {
+		yaffs_put_chunk_in_file(in, inode_chunk, new_chunk_id, 0);
+
+		if (prev_chunk_id > 0)
+			yaffs_chunk_del(dev, prev_chunk_id, 1, __LINE__);
+
+		yaffs_verify_file_sane(in);
+	}
+	return new_chunk_id;
+
+}
+
+
+
+static int yaffs_do_xattrib_mod(struct yaffs_obj *obj, int set,
+				const YCHAR *name, const void *value, int size,
+				int flags)
+{
+	struct yaffs_xattr_mod xmod;
+	int result;
+
+	xmod.set = set;
+	xmod.name = name;
+	xmod.data = value;
+	xmod.size = size;
+	xmod.flags = flags;
+	xmod.result = -ENOSPC;
+
+	result = yaffs_update_oh(obj, NULL, 0, 0, 0, &xmod);
+
+	if (result > 0)
+		return xmod.result;
+	else
+		return -ENOSPC;
+}
+
+static int yaffs_apply_xattrib_mod(struct yaffs_obj *obj, char *buffer,
+				   struct yaffs_xattr_mod *xmod)
+{
+	int retval = 0;
+	int x_offs = sizeof(struct yaffs_obj_hdr);
+	struct yaffs_dev *dev = obj->my_dev;
+	int x_size = dev->data_bytes_per_chunk - sizeof(struct yaffs_obj_hdr);
+	char *x_buffer = buffer + x_offs;
+
+	if (xmod->set)
+		retval =
+		    nval_set(x_buffer, x_size, xmod->name, xmod->data,
+			     xmod->size, xmod->flags);
+	else
+		retval = nval_del(x_buffer, x_size, xmod->name);
+
+	obj->has_xattr = nval_hasvalues(x_buffer, x_size);
+	obj->xattr_known = 1;
+	xmod->result = retval;
+
+	return retval;
+}
+
+static int yaffs_do_xattrib_fetch(struct yaffs_obj *obj, const YCHAR *name,
+				  void *value, int size)
+{
+	char *buffer = NULL;
+	int result;
+	struct yaffs_ext_tags tags;
+	struct yaffs_dev *dev = obj->my_dev;
+	int x_offs = sizeof(struct yaffs_obj_hdr);
+	int x_size = dev->data_bytes_per_chunk - sizeof(struct yaffs_obj_hdr);
+	char *x_buffer;
+	int retval = 0;
+
+	if (obj->hdr_chunk < 1)
+		return -ENODATA;
+
+	/* If we know that the object has no xattribs then don't do all the
+	 * reading and parsing.
+	 */
+	if (obj->xattr_known && !obj->has_xattr) {
+		if (name)
+			return -ENODATA;
+		else
+			return 0;
+	}
+
+	buffer = (char *)yaffs_get_temp_buffer(dev);
+	if (!buffer)
+		return -ENOMEM;
+
+	result =
+	    yaffs_rd_chunk_tags_nand(dev, obj->hdr_chunk, (u8 *) buffer, &tags);
+
+	if (result != YAFFS_OK)
+		retval = -ENOENT;
+	else {
+		x_buffer = buffer + x_offs;
+
+		if (!obj->xattr_known) {
+			obj->has_xattr = nval_hasvalues(x_buffer, x_size);
+			obj->xattr_known = 1;
+		}
+
+		if (name)
+			retval = nval_get(x_buffer, x_size, name, value, size);
+		else
+			retval = nval_list(x_buffer, x_size, value, size);
+	}
+	yaffs_release_temp_buffer(dev, (u8 *) buffer);
+	return retval;
+}
+
+int yaffs_set_xattrib(struct yaffs_obj *obj, const YCHAR * name,
+		      const void *value, int size, int flags)
+{
+	return yaffs_do_xattrib_mod(obj, 1, name, value, size, flags);
+}
+
+int yaffs_remove_xattrib(struct yaffs_obj *obj, const YCHAR * name)
+{
+	return yaffs_do_xattrib_mod(obj, 0, name, NULL, 0, 0);
+}
+
+int yaffs_get_xattrib(struct yaffs_obj *obj, const YCHAR * name, void *value,
+		      int size)
+{
+	return yaffs_do_xattrib_fetch(obj, name, value, size);
+}
+
+int yaffs_list_xattrib(struct yaffs_obj *obj, char *buffer, int size)
+{
+	return yaffs_do_xattrib_fetch(obj, NULL, buffer, size);
+}
+
+static void yaffs_check_obj_details_loaded(struct yaffs_obj *in)
+{
+	u8 *buf;
+	struct yaffs_obj_hdr *oh;
+	struct yaffs_dev *dev;
+	struct yaffs_ext_tags tags;
+	int result;
+	int alloc_failed = 0;
+
+	if (!in || !in->lazy_loaded || in->hdr_chunk < 1)
+		return;
+
+	dev = in->my_dev;
+	in->lazy_loaded = 0;
+	buf = yaffs_get_temp_buffer(dev);
+
+	result = yaffs_rd_chunk_tags_nand(dev, in->hdr_chunk, buf, &tags);
+	oh = (struct yaffs_obj_hdr *)buf;
+
+	in->yst_mode = oh->yst_mode;
+	yaffs_load_attribs(in, oh);
+	yaffs_set_obj_name_from_oh(in, oh);
+
+	if (in->variant_type == YAFFS_OBJECT_TYPE_SYMLINK) {
+		in->variant.symlink_variant.alias =
+		    yaffs_clone_str(oh->alias);
+		if (!in->variant.symlink_variant.alias)
+			alloc_failed = 1;	/* Not returned */
+	}
+	yaffs_release_temp_buffer(dev, buf);
+}
+
+static void yaffs_load_name_from_oh(struct yaffs_dev *dev, YCHAR *name,
+				    const YCHAR *oh_name, int buff_size)
+{
+#ifdef CONFIG_YAFFS_AUTO_UNICODE
+	if (dev->param.auto_unicode) {
+		if (*oh_name) {
+			/* It is an ASCII name, do an ASCII to
+			 * unicode conversion */
+			const char *ascii_oh_name = (const char *)oh_name;
+			int n = buff_size - 1;
+			while (n > 0 && *ascii_oh_name) {
+				*name = *ascii_oh_name;
+				name++;
+				ascii_oh_name++;
+				n--;
+			}
+		} else {
+			strncpy(name, oh_name + 1, buff_size - 1);
+		}
+	} else {
+#else
+	(void) dev;
+	{
+#endif
+		strncpy(name, oh_name, buff_size - 1);
+	}
+}
+
+static void yaffs_load_oh_from_name(struct yaffs_dev *dev, YCHAR *oh_name,
+				    const YCHAR *name)
+{
+#ifdef CONFIG_YAFFS_AUTO_UNICODE
+
+	int is_ascii;
+	YCHAR *w;
+
+	if (dev->param.auto_unicode) {
+
+		is_ascii = 1;
+		w = name;
+
+		/* Figure out if the name will fit in ascii character set */
+		while (is_ascii && *w) {
+			if ((*w) & 0xff00)
+				is_ascii = 0;
+			w++;
+		}
+
+		if (is_ascii) {
+			/* It is an ASCII name, so convert unicode to ascii */
+			char *ascii_oh_name = (char *)oh_name;
+			int n = YAFFS_MAX_NAME_LENGTH - 1;
+			while (n > 0 && *name) {
+				*ascii_oh_name = *name;
+				name++;
+				ascii_oh_name++;
+				n--;
+			}
+		} else {
+			/* Unicode name, so save starting at the second YCHAR */
+			*oh_name = 0;
+			strncpy(oh_name + 1, name, YAFFS_MAX_NAME_LENGTH - 2);
+		}
+	} else {
+#else
+	dev = dev;
+	{
+#endif
+		strncpy(oh_name, name, YAFFS_MAX_NAME_LENGTH - 1);
+	}
+}
+
+/* UpdateObjectHeader updates the header on NAND for an object.
+ * If name is not NULL, then that new name is used.
+ */
+int yaffs_update_oh(struct yaffs_obj *in, const YCHAR *name, int force,
+		    int is_shrink, int shadows, struct yaffs_xattr_mod *xmod)
+{
+
+	struct yaffs_block_info *bi;
+	struct yaffs_dev *dev = in->my_dev;
+	int prev_chunk_id;
+	int ret_val = 0;
+	int result = 0;
+	int new_chunk_id;
+	struct yaffs_ext_tags new_tags;
+	struct yaffs_ext_tags old_tags;
+	const YCHAR *alias = NULL;
+	u8 *buffer = NULL;
+	YCHAR old_name[YAFFS_MAX_NAME_LENGTH + 1];
+	struct yaffs_obj_hdr *oh = NULL;
+	loff_t file_size = 0;
+
+	strcpy(old_name, _Y("silly old name"));
+
+	if (in->fake && in != dev->root_dir && !force && !xmod)
+		return ret_val;
+
+	yaffs_check_gc(dev, 0);
+	yaffs_check_obj_details_loaded(in);
+
+	buffer = yaffs_get_temp_buffer(in->my_dev);
+	oh = (struct yaffs_obj_hdr *)buffer;
+
+	prev_chunk_id = in->hdr_chunk;
+
+	if (prev_chunk_id > 0) {
+		result = yaffs_rd_chunk_tags_nand(dev, prev_chunk_id,
+						  buffer, &old_tags);
+
+		yaffs_verify_oh(in, oh, &old_tags, 0);
+		memcpy(old_name, oh->name, sizeof(oh->name));
+		memset(buffer, 0xff, sizeof(struct yaffs_obj_hdr));
+	} else {
+		memset(buffer, 0xff, dev->data_bytes_per_chunk);
+	}
+
+	oh->type = in->variant_type;
+	oh->yst_mode = in->yst_mode;
+	oh->shadows_obj = oh->inband_shadowed_obj_id = shadows;
+
+	yaffs_load_attribs_oh(oh, in);
+
+	if (in->parent)
+		oh->parent_obj_id = in->parent->obj_id;
+	else
+		oh->parent_obj_id = 0;
+
+	if (name && *name) {
+		memset(oh->name, 0, sizeof(oh->name));
+		yaffs_load_oh_from_name(dev, oh->name, name);
+	} else if (prev_chunk_id > 0) {
+		memcpy(oh->name, old_name, sizeof(oh->name));
+	} else {
+		memset(oh->name, 0, sizeof(oh->name));
+	}
+
+	oh->is_shrink = is_shrink;
+
+	switch (in->variant_type) {
+	case YAFFS_OBJECT_TYPE_UNKNOWN:
+		/* Should not happen */
+		break;
+	case YAFFS_OBJECT_TYPE_FILE:
+		if (oh->parent_obj_id != YAFFS_OBJECTID_DELETED &&
+		    oh->parent_obj_id != YAFFS_OBJECTID_UNLINKED)
+			file_size = in->variant.file_variant.file_size;
+		yaffs_oh_size_load(oh, file_size);
+		break;
+	case YAFFS_OBJECT_TYPE_HARDLINK:
+		oh->equiv_id = in->variant.hardlink_variant.equiv_id;
+		break;
+	case YAFFS_OBJECT_TYPE_SPECIAL:
+		/* Do nothing */
+		break;
+	case YAFFS_OBJECT_TYPE_DIRECTORY:
+		/* Do nothing */
+		break;
+	case YAFFS_OBJECT_TYPE_SYMLINK:
+		alias = in->variant.symlink_variant.alias;
+		if (!alias)
+			alias = _Y("no alias");
+		strncpy(oh->alias, alias, YAFFS_MAX_ALIAS_LENGTH);
+		oh->alias[YAFFS_MAX_ALIAS_LENGTH] = 0;
+		break;
+	}
+
+	/* process any xattrib modifications */
+	if (xmod)
+		yaffs_apply_xattrib_mod(in, (char *)buffer, xmod);
+
+	/* Tags */
+	memset(&new_tags, 0, sizeof(new_tags));
+	in->serial++;
+	new_tags.chunk_id = 0;
+	new_tags.obj_id = in->obj_id;
+	new_tags.serial_number = in->serial;
+
+	/* Add extra info for file header */
+	new_tags.extra_available = 1;
+	new_tags.extra_parent_id = oh->parent_obj_id;
+	new_tags.extra_file_size = file_size;
+	new_tags.extra_is_shrink = oh->is_shrink;
+	new_tags.extra_equiv_id = oh->equiv_id;
+	new_tags.extra_shadows = (oh->shadows_obj > 0) ? 1 : 0;
+	new_tags.extra_obj_type = in->variant_type;
+	yaffs_verify_oh(in, oh, &new_tags, 1);
+
+	/* Create new chunk in NAND */
+	new_chunk_id =
+	    yaffs_write_new_chunk(dev, buffer, &new_tags,
+				  (prev_chunk_id > 0) ? 1 : 0);
+
+	if (buffer)
+		yaffs_release_temp_buffer(dev, buffer);
+
+	if (new_chunk_id < 0)
+		return new_chunk_id;
+
+	in->hdr_chunk = new_chunk_id;
+
+	if (prev_chunk_id > 0)
+		yaffs_chunk_del(dev, prev_chunk_id, 1, __LINE__);
+
+	if (!yaffs_obj_cache_dirty(in))
+		in->dirty = 0;
+
+	/* If this was a shrink, then mark the block
+	 * that the chunk lives on */
+	if (is_shrink) {
+		bi = yaffs_get_block_info(in->my_dev,
+					  new_chunk_id /
+					  in->my_dev->param.chunks_per_block);
+		bi->has_shrink_hdr = 1;
+	}
+
+
+	return new_chunk_id;
+}
+
+/*--------------------- File read/write ------------------------
+ * Read and write have very similar structures.
+ * In general the read/write has three parts to it
+ * An incomplete chunk to start with (if the read/write is not chunk-aligned)
+ * Some complete chunks
+ * An incomplete chunk to end off with
+ *
+ * Curve-balls: the first chunk might also be the last chunk.
+ */
+
+int yaffs_file_rd(struct yaffs_obj *in, u8 * buffer, loff_t offset, int n_bytes)
+{
+	int chunk;
+	u32 start;
+	int n_copy;
+	int n = n_bytes;
+	int n_done = 0;
+	struct yaffs_cache *cache;
+	struct yaffs_dev *dev;
+
+	dev = in->my_dev;
+
+	while (n > 0) {
+		yaffs_addr_to_chunk(dev, offset, &chunk, &start);
+		chunk++;
+
+		/* OK now check for the curveball where the start and end are in
+		 * the same chunk.
+		 */
+		if ((start + n) < dev->data_bytes_per_chunk)
+			n_copy = n;
+		else
+			n_copy = dev->data_bytes_per_chunk - start;
+
+		cache = yaffs_find_chunk_cache(in, chunk);
+
+		/* If the chunk is already in the cache or it is less than
+		 * a whole chunk or we're using inband tags then use the cache
+		 * (if there is caching) else bypass the cache.
+		 */
+		if (cache || n_copy != dev->data_bytes_per_chunk ||
+		    dev->param.inband_tags) {
+			if (dev->param.n_caches > 0) {
+
+				/* If we can't find the data in the cache,
+				 * then load it up. */
+
+				if (!cache) {
+					cache =
+					    yaffs_grab_chunk_cache(in->my_dev);
+					cache->object = in;
+					cache->chunk_id = chunk;
+					cache->dirty = 0;
+					cache->locked = 0;
+					yaffs_rd_data_obj(in, chunk,
+							  cache->data);
+					cache->n_bytes = 0;
+				}
+
+				yaffs_use_cache(dev, cache, 0);
+
+				cache->locked = 1;
+
+				memcpy(buffer, &cache->data[start], n_copy);
+
+				cache->locked = 0;
+			} else {
+				/* Read into the local buffer then copy.. */
+
+				u8 *local_buffer =
+				    yaffs_get_temp_buffer(dev);
+				yaffs_rd_data_obj(in, chunk, local_buffer);
+
+				memcpy(buffer, &local_buffer[start], n_copy);
+
+				yaffs_release_temp_buffer(dev, local_buffer);
+			}
+		} else {
+			/* A full chunk. Read directly into the buffer. */
+			yaffs_rd_data_obj(in, chunk, buffer);
+		}
+		n -= n_copy;
+		offset += n_copy;
+		buffer += n_copy;
+		n_done += n_copy;
+	}
+	return n_done;
+}
+
+int yaffs_do_file_wr(struct yaffs_obj *in, const u8 *buffer, loff_t offset,
+		     int n_bytes, int write_through)
+{
+
+	int chunk;
+	u32 start;
+	int n_copy;
+	int n = n_bytes;
+	int n_done = 0;
+	int n_writeback;
+	loff_t start_write = offset;
+	int chunk_written = 0;
+	u32 n_bytes_read;
+	loff_t chunk_start;
+	struct yaffs_dev *dev;
+
+	dev = in->my_dev;
+
+	while (n > 0 && chunk_written >= 0) {
+		yaffs_addr_to_chunk(dev, offset, &chunk, &start);
+
+		if (((loff_t)chunk) *
+		    dev->data_bytes_per_chunk + start != offset ||
+		    start >= dev->data_bytes_per_chunk) {
+			yaffs_trace(YAFFS_TRACE_ERROR,
+				"AddrToChunk of offset %lld gives chunk %d start %d",
+				offset, chunk, start);
+		}
+		chunk++;	/* File pos to chunk in file offset */
+
+		/* OK now check for the curveball where the start and end are in
+		 * the same chunk.
+		 */
+
+		if ((start + n) < dev->data_bytes_per_chunk) {
+			n_copy = n;
+
+			/* Now calculate how many bytes to write back....
+			 * If we're overwriting and not writing to then end of
+			 * file then we need to write back as much as was there
+			 * before.
+			 */
+
+			chunk_start = (((loff_t)(chunk - 1)) *
+					dev->data_bytes_per_chunk);
+
+			if (chunk_start > in->variant.file_variant.file_size)
+				n_bytes_read = 0;	/* Past end of file */
+			else
+				n_bytes_read =
+				    in->variant.file_variant.file_size -
+				    chunk_start;
+
+			if (n_bytes_read > dev->data_bytes_per_chunk)
+				n_bytes_read = dev->data_bytes_per_chunk;
+
+			n_writeback =
+			    (n_bytes_read >
+			     (start + n)) ? n_bytes_read : (start + n);
+
+			if (n_writeback < 0 ||
+			    n_writeback > dev->data_bytes_per_chunk)
+				BUG();
+
+		} else {
+			n_copy = dev->data_bytes_per_chunk - start;
+			n_writeback = dev->data_bytes_per_chunk;
+		}
+
+		if (n_copy != dev->data_bytes_per_chunk ||
+		    dev->param.inband_tags) {
+			/* An incomplete start or end chunk (or maybe both
+			 * start and end chunk), or we're using inband tags,
+			 * so we want to use the cache buffers.
+			 */
+			if (dev->param.n_caches > 0) {
+				struct yaffs_cache *cache;
+
+				/* If we can't find the data in the cache, then
+				 * load the cache */
+				cache = yaffs_find_chunk_cache(in, chunk);
+
+				if (!cache &&
+				    yaffs_check_alloc_available(dev, 1)) {
+					cache = yaffs_grab_chunk_cache(dev);
+					cache->object = in;
+					cache->chunk_id = chunk;
+					cache->dirty = 0;
+					cache->locked = 0;
+					yaffs_rd_data_obj(in, chunk,
+							  cache->data);
+				} else if (cache &&
+					   !cache->dirty &&
+					   !yaffs_check_alloc_available(dev,
+									1)) {
+					/* Drop the cache if it was a read cache
+					 * item and no space check has been made
+					 * for it.
+					 */
+					cache = NULL;
+				}
+
+				if (cache) {
+					yaffs_use_cache(dev, cache, 1);
+					cache->locked = 1;
+
+					memcpy(&cache->data[start], buffer,
+					       n_copy);
+
+					cache->locked = 0;
+					cache->n_bytes = n_writeback;
+
+					if (write_through) {
+						chunk_written =
+						    yaffs_wr_data_obj
+						    (cache->object,
+						     cache->chunk_id,
+						     cache->data,
+						     cache->n_bytes, 1);
+						cache->dirty = 0;
+					}
+				} else {
+					chunk_written = -1;	/* fail write */
+				}
+			} else {
+				/* An incomplete start or end chunk (or maybe
+				 * both start and end chunk). Read into the
+				 * local buffer then copy over and write back.
+				 */
+
+				u8 *local_buffer = yaffs_get_temp_buffer(dev);
+
+				yaffs_rd_data_obj(in, chunk, local_buffer);
+				memcpy(&local_buffer[start], buffer, n_copy);
+
+				chunk_written =
+				    yaffs_wr_data_obj(in, chunk,
+						      local_buffer,
+						      n_writeback, 0);
+
+				yaffs_release_temp_buffer(dev, local_buffer);
+			}
+		} else {
+			/* A full chunk. Write directly from the buffer. */
+
+			chunk_written =
+			    yaffs_wr_data_obj(in, chunk, buffer,
+					      dev->data_bytes_per_chunk, 0);
+
+			/* Since we've overwritten the cached data,
+			 * we better invalidate it. */
+			yaffs_invalidate_chunk_cache(in, chunk);
+		}
+
+		if (chunk_written >= 0) {
+			n -= n_copy;
+			offset += n_copy;
+			buffer += n_copy;
+			n_done += n_copy;
+		}
+	}
+
+	/* Update file object */
+
+	if ((start_write + n_done) > in->variant.file_variant.file_size)
+		in->variant.file_variant.file_size = (start_write + n_done);
+
+	in->dirty = 1;
+	return n_done;
+}
+
+int yaffs_wr_file(struct yaffs_obj *in, const u8 *buffer, loff_t offset,
+		  int n_bytes, int write_through)
+{
+	yaffs2_handle_hole(in, offset);
+	return yaffs_do_file_wr(in, buffer, offset, n_bytes, write_through);
+}
+
+/* ---------------------- File resizing stuff ------------------ */
+
+static void yaffs_prune_chunks(struct yaffs_obj *in, loff_t new_size)
+{
+
+	struct yaffs_dev *dev = in->my_dev;
+	loff_t old_size = in->variant.file_variant.file_size;
+	int i;
+	int chunk_id;
+	u32 dummy;
+	int last_del;
+	int start_del;
+
+	if (old_size > 0)
+		yaffs_addr_to_chunk(dev, old_size - 1, &last_del, &dummy);
+	else
+		last_del = 0;
+
+	yaffs_addr_to_chunk(dev, new_size + dev->data_bytes_per_chunk - 1,
+				&start_del, &dummy);
+	last_del++;
+	start_del++;
+
+	/* Delete backwards so that we don't end up with holes if
+	 * power is lost part-way through the operation.
+	 */
+	for (i = last_del; i >= start_del; i--) {
+		/* NB this could be optimised somewhat,
+		 * eg. could retrieve the tags and write them without
+		 * using yaffs_chunk_del
+		 */
+
+		chunk_id = yaffs_find_del_file_chunk(in, i, NULL);
+
+		if (chunk_id < 1)
+			continue;
+
+		if (chunk_id <
+		    (dev->internal_start_block * dev->param.chunks_per_block) ||
+		    chunk_id >=
+		    ((dev->internal_end_block + 1) *
+		      dev->param.chunks_per_block)) {
+			yaffs_trace(YAFFS_TRACE_ALWAYS,
+				"Found daft chunk_id %d for %d",
+				chunk_id, i);
+		} else {
+			in->n_data_chunks--;
+			yaffs_chunk_del(dev, chunk_id, 1, __LINE__);
+		}
+	}
+}
+
+void yaffs_resize_file_down(struct yaffs_obj *obj, loff_t new_size)
+{
+	int new_full;
+	u32 new_partial;
+	struct yaffs_dev *dev = obj->my_dev;
+
+	yaffs_addr_to_chunk(dev, new_size, &new_full, &new_partial);
+
+	yaffs_prune_chunks(obj, new_size);
+
+	if (new_partial != 0) {
+		int last_chunk = 1 + new_full;
+		u8 *local_buffer = yaffs_get_temp_buffer(dev);
+
+		/* Rewrite the last chunk with its new size and zero pad */
+		yaffs_rd_data_obj(obj, last_chunk, local_buffer);
+		memset(local_buffer + new_partial, 0,
+		       dev->data_bytes_per_chunk - new_partial);
+
+		yaffs_wr_data_obj(obj, last_chunk, local_buffer,
+				  new_partial, 1);
+
+		yaffs_release_temp_buffer(dev, local_buffer);
+	}
+
+	obj->variant.file_variant.file_size = new_size;
+
+	yaffs_prune_tree(dev, &obj->variant.file_variant);
+}
+
+int yaffs_resize_file(struct yaffs_obj *in, loff_t new_size)
+{
+	struct yaffs_dev *dev = in->my_dev;
+	loff_t old_size = in->variant.file_variant.file_size;
+
+	yaffs_flush_file_cache(in);
+	yaffs_invalidate_whole_cache(in);
+
+	yaffs_check_gc(dev, 0);
+
+	if (in->variant_type != YAFFS_OBJECT_TYPE_FILE)
+		return YAFFS_FAIL;
+
+	if (new_size == old_size)
+		return YAFFS_OK;
+
+	if (new_size > old_size) {
+		yaffs2_handle_hole(in, new_size);
+		in->variant.file_variant.file_size = new_size;
+	} else {
+		/* new_size < old_size */
+		yaffs_resize_file_down(in, new_size);
+	}
+
+	/* Write a new object header to reflect the resize.
+	 * show we've shrunk the file, if need be
+	 * Do this only if the file is not in the deleted directories
+	 * and is not shadowed.
+	 */
+	if (in->parent &&
+	    !in->is_shadowed &&
+	    in->parent->obj_id != YAFFS_OBJECTID_UNLINKED &&
+	    in->parent->obj_id != YAFFS_OBJECTID_DELETED)
+		yaffs_update_oh(in, NULL, 0, 0, 0, NULL);
+
+	return YAFFS_OK;
+}
+
+int yaffs_flush_file(struct yaffs_obj *in, int update_time, int data_sync)
+{
+	if (!in->dirty)
+		return YAFFS_OK;
+
+	yaffs_flush_file_cache(in);
+
+	if (data_sync)
+		return YAFFS_OK;
+
+	if (update_time)
+		yaffs_load_current_time(in, 0, 0);
+
+	return (yaffs_update_oh(in, NULL, 0, 0, 0, NULL) >= 0) ?
+				YAFFS_OK : YAFFS_FAIL;
+}
+
+
+/* yaffs_del_file deletes the whole file data
+ * and the inode associated with the file.
+ * It does not delete the links associated with the file.
+ */
+static int yaffs_unlink_file_if_needed(struct yaffs_obj *in)
+{
+	int ret_val;
+	int del_now = 0;
+	struct yaffs_dev *dev = in->my_dev;
+
+	if (!in->my_inode)
+		del_now = 1;
+
+	if (del_now) {
+		ret_val =
+		    yaffs_change_obj_name(in, in->my_dev->del_dir,
+					  _Y("deleted"), 0, 0);
+		yaffs_trace(YAFFS_TRACE_TRACING,
+			"yaffs: immediate deletion of file %d",
+			in->obj_id);
+		in->deleted = 1;
+		in->my_dev->n_deleted_files++;
+		if (dev->param.disable_soft_del || dev->param.is_yaffs2)
+			yaffs_resize_file(in, 0);
+		yaffs_soft_del_file(in);
+	} else {
+		ret_val =
+		    yaffs_change_obj_name(in, in->my_dev->unlinked_dir,
+					  _Y("unlinked"), 0, 0);
+	}
+	return ret_val;
+}
+
+static int yaffs_del_file(struct yaffs_obj *in)
+{
+	int ret_val = YAFFS_OK;
+	int deleted;	/* Need to cache value on stack if in is freed */
+	struct yaffs_dev *dev = in->my_dev;
+
+	if (dev->param.disable_soft_del || dev->param.is_yaffs2)
+		yaffs_resize_file(in, 0);
+
+	if (in->n_data_chunks > 0) {
+		/* Use soft deletion if there is data in the file.
+		 * That won't be the case if it has been resized to zero.
+		 */
+		if (!in->unlinked)
+			ret_val = yaffs_unlink_file_if_needed(in);
+
+		deleted = in->deleted;
+
+		if (ret_val == YAFFS_OK && in->unlinked && !in->deleted) {
+			in->deleted = 1;
+			deleted = 1;
+			in->my_dev->n_deleted_files++;
+			yaffs_soft_del_file(in);
+		}
+		return deleted ? YAFFS_OK : YAFFS_FAIL;
+	} else {
+		/* The file has no data chunks so we toss it immediately */
+		yaffs_free_tnode(in->my_dev, in->variant.file_variant.top);
+		in->variant.file_variant.top = NULL;
+		yaffs_generic_obj_del(in);
+
+		return YAFFS_OK;
+	}
+}
+
+int yaffs_is_non_empty_dir(struct yaffs_obj *obj)
+{
+	return (obj &&
+		obj->variant_type == YAFFS_OBJECT_TYPE_DIRECTORY) &&
+		!(list_empty(&obj->variant.dir_variant.children));
+}
+
+static int yaffs_del_dir(struct yaffs_obj *obj)
+{
+	/* First check that the directory is empty. */
+	if (yaffs_is_non_empty_dir(obj))
+		return YAFFS_FAIL;
+
+	return yaffs_generic_obj_del(obj);
+}
+
+static int yaffs_del_symlink(struct yaffs_obj *in)
+{
+	kfree(in->variant.symlink_variant.alias);
+	in->variant.symlink_variant.alias = NULL;
+
+	return yaffs_generic_obj_del(in);
+}
+
+static int yaffs_del_link(struct yaffs_obj *in)
+{
+	/* remove this hardlink from the list associated with the equivalent
+	 * object
+	 */
+	list_del_init(&in->hard_links);
+	return yaffs_generic_obj_del(in);
+}
+
+int yaffs_del_obj(struct yaffs_obj *obj)
+{
+	int ret_val = -1;
+
+	switch (obj->variant_type) {
+	case YAFFS_OBJECT_TYPE_FILE:
+		ret_val = yaffs_del_file(obj);
+		break;
+	case YAFFS_OBJECT_TYPE_DIRECTORY:
+		if (!list_empty(&obj->variant.dir_variant.dirty)) {
+			yaffs_trace(YAFFS_TRACE_BACKGROUND,
+				"Remove object %d from dirty directories",
+				obj->obj_id);
+			list_del_init(&obj->variant.dir_variant.dirty);
+		}
+		return yaffs_del_dir(obj);
+		break;
+	case YAFFS_OBJECT_TYPE_SYMLINK:
+		ret_val = yaffs_del_symlink(obj);
+		break;
+	case YAFFS_OBJECT_TYPE_HARDLINK:
+		ret_val = yaffs_del_link(obj);
+		break;
+	case YAFFS_OBJECT_TYPE_SPECIAL:
+		ret_val = yaffs_generic_obj_del(obj);
+		break;
+	case YAFFS_OBJECT_TYPE_UNKNOWN:
+		ret_val = 0;
+		break;		/* should not happen. */
+	}
+	return ret_val;
+}
+
+static int yaffs_unlink_worker(struct yaffs_obj *obj)
+{
+	int del_now = 0;
+
+	if (!obj)
+		return YAFFS_FAIL;
+
+	if (!obj->my_inode)
+		del_now = 1;
+
+	yaffs_update_parent(obj->parent);
+
+	if (obj->variant_type == YAFFS_OBJECT_TYPE_HARDLINK) {
+		return yaffs_del_link(obj);
+	} else if (!list_empty(&obj->hard_links)) {
+		/* Curve ball: We're unlinking an object that has a hardlink.
+		 *
+		 * This problem arises because we are not strictly following
+		 * The Linux link/inode model.
+		 *
+		 * We can't really delete the object.
+		 * Instead, we do the following:
+		 * - Select a hardlink.
+		 * - Unhook it from the hard links
+		 * - Move it from its parent directory so that the rename works.
+		 * - Rename the object to the hardlink's name.
+		 * - Delete the hardlink
+		 */
+
+		struct yaffs_obj *hl;
+		struct yaffs_obj *parent;
+		int ret_val;
+		YCHAR name[YAFFS_MAX_NAME_LENGTH + 1];
+
+		hl = list_entry(obj->hard_links.next, struct yaffs_obj,
+				hard_links);
+
+		yaffs_get_obj_name(hl, name, YAFFS_MAX_NAME_LENGTH + 1);
+		parent = hl->parent;
+
+		list_del_init(&hl->hard_links);
+
+		yaffs_add_obj_to_dir(obj->my_dev->unlinked_dir, hl);
+
+		ret_val = yaffs_change_obj_name(obj, parent, name, 0, 0);
+
+		if (ret_val == YAFFS_OK)
+			ret_val = yaffs_generic_obj_del(hl);
+
+		return ret_val;
+
+	} else if (del_now) {
+		switch (obj->variant_type) {
+		case YAFFS_OBJECT_TYPE_FILE:
+			return yaffs_del_file(obj);
+			break;
+		case YAFFS_OBJECT_TYPE_DIRECTORY:
+			list_del_init(&obj->variant.dir_variant.dirty);
+			return yaffs_del_dir(obj);
+			break;
+		case YAFFS_OBJECT_TYPE_SYMLINK:
+			return yaffs_del_symlink(obj);
+			break;
+		case YAFFS_OBJECT_TYPE_SPECIAL:
+			return yaffs_generic_obj_del(obj);
+			break;
+		case YAFFS_OBJECT_TYPE_HARDLINK:
+		case YAFFS_OBJECT_TYPE_UNKNOWN:
+		default:
+			return YAFFS_FAIL;
+		}
+	} else if (yaffs_is_non_empty_dir(obj)) {
+		return YAFFS_FAIL;
+	} else {
+		return yaffs_change_obj_name(obj, obj->my_dev->unlinked_dir,
+						_Y("unlinked"), 0, 0);
+	}
+}
+
+static int yaffs_unlink_obj(struct yaffs_obj *obj)
+{
+	if (obj && obj->unlink_allowed)
+		return yaffs_unlink_worker(obj);
+
+	return YAFFS_FAIL;
+}
+
+int yaffs_unlinker(struct yaffs_obj *dir, const YCHAR *name)
+{
+	struct yaffs_obj *obj;
+
+	obj = yaffs_find_by_name(dir, name);
+	return yaffs_unlink_obj(obj);
+}
+
+/* Note:
+ * If old_name is NULL then we take old_dir as the object to be renamed.
+ */
+int yaffs_rename_obj(struct yaffs_obj *old_dir, const YCHAR *old_name,
+		     struct yaffs_obj *new_dir, const YCHAR *new_name)
+{
+	struct yaffs_obj *obj = NULL;
+	struct yaffs_obj *existing_target = NULL;
+	int force = 0;
+	int result;
+	struct yaffs_dev *dev;
+
+	if (!old_dir || old_dir->variant_type != YAFFS_OBJECT_TYPE_DIRECTORY) {
+		BUG();
+		return YAFFS_FAIL;
+	}
+	if (!new_dir || new_dir->variant_type != YAFFS_OBJECT_TYPE_DIRECTORY) {
+		BUG();
+		return YAFFS_FAIL;
+	}
+
+	dev = old_dir->my_dev;
+
+#ifdef CONFIG_YAFFS_CASE_INSENSITIVE
+	/* Special case for case insemsitive systems.
+	 * While look-up is case insensitive, the name isn't.
+	 * Therefore we might want to change x.txt to X.txt
+	 */
+	if (old_dir == new_dir &&
+		old_name && new_name &&
+		strcmp(old_name, new_name) == 0)
+		force = 1;
+#endif
+
+	if (strnlen(new_name, YAFFS_MAX_NAME_LENGTH + 1) >
+	    YAFFS_MAX_NAME_LENGTH)
+		/* ENAMETOOLONG */
+		return YAFFS_FAIL;
+
+	if (old_name)
+		obj = yaffs_find_by_name(old_dir, old_name);
+	else{
+		obj = old_dir;
+		old_dir = obj->parent;
+	}
+
+	if (obj && obj->rename_allowed) {
+		/* Now handle an existing target, if there is one */
+		existing_target = yaffs_find_by_name(new_dir, new_name);
+		if (yaffs_is_non_empty_dir(existing_target)) {
+			return YAFFS_FAIL;	/* ENOTEMPTY */
+		} else if (existing_target && existing_target != obj) {
+			/* Nuke the target first, using shadowing,
+			 * but only if it isn't the same object.
+			 *
+			 * Note we must disable gc here otherwise it can mess
+			 * up the shadowing.
+			 *
+			 */
+			dev->gc_disable = 1;
+			yaffs_change_obj_name(obj, new_dir, new_name, force,
+					      existing_target->obj_id);
+			existing_target->is_shadowed = 1;
+			yaffs_unlink_obj(existing_target);
+			dev->gc_disable = 0;
+		}
+
+		result = yaffs_change_obj_name(obj, new_dir, new_name, 1, 0);
+
+		yaffs_update_parent(old_dir);
+		if (new_dir != old_dir)
+			yaffs_update_parent(new_dir);
+
+		return result;
+	}
+	return YAFFS_FAIL;
+}
+
+/*----------------------- Initialisation Scanning ---------------------- */
+
+void yaffs_handle_shadowed_obj(struct yaffs_dev *dev, int obj_id,
+			       int backward_scanning)
+{
+	struct yaffs_obj *obj;
+
+	if (backward_scanning) {
+		/* Handle YAFFS2 case (backward scanning)
+		 * If the shadowed object exists then ignore.
+		 */
+		obj = yaffs_find_by_number(dev, obj_id);
+		if (obj)
+			return;
+	}
+
+	/* Let's create it (if it does not exist) assuming it is a file so that
+	 * it can do shrinking etc.
+	 * We put it in unlinked dir to be cleaned up after the scanning
+	 */
+	obj =
+	    yaffs_find_or_create_by_number(dev, obj_id, YAFFS_OBJECT_TYPE_FILE);
+	if (!obj)
+		return;
+	obj->is_shadowed = 1;
+	yaffs_add_obj_to_dir(dev->unlinked_dir, obj);
+	obj->variant.file_variant.shrink_size = 0;
+	obj->valid = 1;		/* So that we don't read any other info. */
+}
+
+void yaffs_link_fixup(struct yaffs_dev *dev, struct list_head *hard_list)
+{
+	struct list_head *lh;
+	struct list_head *save;
+	struct yaffs_obj *hl;
+	struct yaffs_obj *in;
+
+	list_for_each_safe(lh, save, hard_list) {
+		hl = list_entry(lh, struct yaffs_obj, hard_links);
+		in = yaffs_find_by_number(dev,
+					hl->variant.hardlink_variant.equiv_id);
+
+		if (in) {
+			/* Add the hardlink pointers */
+			hl->variant.hardlink_variant.equiv_obj = in;
+			list_add(&hl->hard_links, &in->hard_links);
+		} else {
+			/* Todo Need to report/handle this better.
+			 * Got a problem... hardlink to a non-existant object
+			 */
+			hl->variant.hardlink_variant.equiv_obj = NULL;
+			INIT_LIST_HEAD(&hl->hard_links);
+		}
+	}
+}
+
+static void yaffs_strip_deleted_objs(struct yaffs_dev *dev)
+{
+	/*
+	 *  Sort out state of unlinked and deleted objects after scanning.
+	 */
+	struct list_head *i;
+	struct list_head *n;
+	struct yaffs_obj *l;
+
+	if (dev->read_only)
+		return;
+
+	/* Soft delete all the unlinked files */
+	list_for_each_safe(i, n,
+			   &dev->unlinked_dir->variant.dir_variant.children) {
+		l = list_entry(i, struct yaffs_obj, siblings);
+		yaffs_del_obj(l);
+	}
+
+	list_for_each_safe(i, n, &dev->del_dir->variant.dir_variant.children) {
+		l = list_entry(i, struct yaffs_obj, siblings);
+		yaffs_del_obj(l);
+	}
+}
+
+/*
+ * This code iterates through all the objects making sure that they are rooted.
+ * Any unrooted objects are re-rooted in lost+found.
+ * An object needs to be in one of:
+ * - Directly under deleted, unlinked
+ * - Directly or indirectly under root.
+ *
+ * Note:
+ *  This code assumes that we don't ever change the current relationships
+ *  between directories:
+ *   root_dir->parent == unlinked_dir->parent == del_dir->parent == NULL
+ *   lost-n-found->parent == root_dir
+ *
+ * This fixes the problem where directories might have inadvertently been
+ * deleted leaving the object "hanging" without being rooted in the
+ * directory tree.
+ */
+
+static int yaffs_has_null_parent(struct yaffs_dev *dev, struct yaffs_obj *obj)
+{
+	return (obj == dev->del_dir ||
+		obj == dev->unlinked_dir || obj == dev->root_dir);
+}
+
+static void yaffs_fix_hanging_objs(struct yaffs_dev *dev)
+{
+	struct yaffs_obj *obj;
+	struct yaffs_obj *parent;
+	int i;
+	struct list_head *lh;
+	struct list_head *n;
+	int depth_limit;
+	int hanging;
+
+	if (dev->read_only)
+		return;
+
+	/* Iterate through the objects in each hash entry,
+	 * looking at each object.
+	 * Make sure it is rooted.
+	 */
+
+	for (i = 0; i < YAFFS_NOBJECT_BUCKETS; i++) {
+		list_for_each_safe(lh, n, &dev->obj_bucket[i].list) {
+			obj = list_entry(lh, struct yaffs_obj, hash_link);
+			parent = obj->parent;
+
+			if (yaffs_has_null_parent(dev, obj)) {
+				/* These directories are not hanging */
+				hanging = 0;
+			} else if (!parent ||
+				   parent->variant_type !=
+				   YAFFS_OBJECT_TYPE_DIRECTORY) {
+				hanging = 1;
+			} else if (yaffs_has_null_parent(dev, parent)) {
+				hanging = 0;
+			} else {
+				/*
+				 * Need to follow the parent chain to
+				 * see if it is hanging.
+				 */
+				hanging = 0;
+				depth_limit = 100;
+
+				while (parent != dev->root_dir &&
+				       parent->parent &&
+				       parent->parent->variant_type ==
+				       YAFFS_OBJECT_TYPE_DIRECTORY &&
+				       depth_limit > 0) {
+					parent = parent->parent;
+					depth_limit--;
+				}
+				if (parent != dev->root_dir)
+					hanging = 1;
+			}
+			if (hanging) {
+				yaffs_trace(YAFFS_TRACE_SCAN,
+					"Hanging object %d moved to lost and found",
+					obj->obj_id);
+				yaffs_add_obj_to_dir(dev->lost_n_found, obj);
+			}
+		}
+	}
+}
+
+/*
+ * Delete directory contents for cleaning up lost and found.
+ */
+static void yaffs_del_dir_contents(struct yaffs_obj *dir)
+{
+	struct yaffs_obj *obj;
+	struct list_head *lh;
+	struct list_head *n;
+
+	if (dir->variant_type != YAFFS_OBJECT_TYPE_DIRECTORY)
+		BUG();
+
+	list_for_each_safe(lh, n, &dir->variant.dir_variant.children) {
+		obj = list_entry(lh, struct yaffs_obj, siblings);
+		if (obj->variant_type == YAFFS_OBJECT_TYPE_DIRECTORY)
+			yaffs_del_dir_contents(obj);
+		yaffs_trace(YAFFS_TRACE_SCAN,
+			"Deleting lost_found object %d",
+			obj->obj_id);
+		yaffs_unlink_obj(obj);
+	}
+}
+
+static void yaffs_empty_l_n_f(struct yaffs_dev *dev)
+{
+	yaffs_del_dir_contents(dev->lost_n_found);
+}
+
+
+struct yaffs_obj *yaffs_find_by_name(struct yaffs_obj *directory,
+				     const YCHAR *name)
+{
+	int sum;
+	struct list_head *i;
+	YCHAR buffer[YAFFS_MAX_NAME_LENGTH + 1];
+	struct yaffs_obj *l;
+
+	if (!name)
+		return NULL;
+
+	if (!directory) {
+		yaffs_trace(YAFFS_TRACE_ALWAYS,
+			"tragedy: yaffs_find_by_name: null pointer directory"
+			);
+		BUG();
+		return NULL;
+	}
+	if (directory->variant_type != YAFFS_OBJECT_TYPE_DIRECTORY) {
+		yaffs_trace(YAFFS_TRACE_ALWAYS,
+			"tragedy: yaffs_find_by_name: non-directory"
+			);
+		BUG();
+	}
+
+	sum = yaffs_calc_name_sum(name);
+
+	list_for_each(i, &directory->variant.dir_variant.children) {
+		l = list_entry(i, struct yaffs_obj, siblings);
+
+		if (l->parent != directory)
+			BUG();
+
+		yaffs_check_obj_details_loaded(l);
+
+		/* Special case for lost-n-found */
+		if (l->obj_id == YAFFS_OBJECTID_LOSTNFOUND) {
+			if (!strcmp(name, YAFFS_LOSTNFOUND_NAME))
+				return l;
+		} else if (l->sum == sum || l->hdr_chunk <= 0) {
+			/* LostnFound chunk called Objxxx
+			 * Do a real check
+			 */
+			yaffs_get_obj_name(l, buffer,
+				YAFFS_MAX_NAME_LENGTH + 1);
+			if (!strncmp(name, buffer, YAFFS_MAX_NAME_LENGTH))
+				return l;
+		}
+	}
+	return NULL;
+}
+
+/* GetEquivalentObject dereferences any hard links to get to the
+ * actual object.
+ */
+
+struct yaffs_obj *yaffs_get_equivalent_obj(struct yaffs_obj *obj)
+{
+	if (obj && obj->variant_type == YAFFS_OBJECT_TYPE_HARDLINK) {
+		obj = obj->variant.hardlink_variant.equiv_obj;
+		yaffs_check_obj_details_loaded(obj);
+	}
+	return obj;
+}
+
+/*
+ *  A note or two on object names.
+ *  * If the object name is missing, we then make one up in the form objnnn
+ *
+ *  * ASCII names are stored in the object header's name field from byte zero
+ *  * Unicode names are historically stored starting from byte zero.
+ *
+ * Then there are automatic Unicode names...
+ * The purpose of these is to save names in a way that can be read as
+ * ASCII or Unicode names as appropriate, thus allowing a Unicode and ASCII
+ * system to share files.
+ *
+ * These automatic unicode are stored slightly differently...
+ *  - If the name can fit in the ASCII character space then they are saved as
+ *    ascii names as per above.
+ *  - If the name needs Unicode then the name is saved in Unicode
+ *    starting at oh->name[1].
+
+ */
+static void yaffs_fix_null_name(struct yaffs_obj *obj, YCHAR *name,
+				int buffer_size)
+{
+	/* Create an object name if we could not find one. */
+	if (strnlen(name, YAFFS_MAX_NAME_LENGTH) == 0) {
+		YCHAR local_name[20];
+		YCHAR num_string[20];
+		YCHAR *x = &num_string[19];
+		unsigned v = obj->obj_id;
+		num_string[19] = 0;
+		while (v > 0) {
+			x--;
+			*x = '0' + (v % 10);
+			v /= 10;
+		}
+		/* make up a name */
+		strcpy(local_name, YAFFS_LOSTNFOUND_PREFIX);
+		strcat(local_name, x);
+		strncpy(name, local_name, buffer_size - 1);
+	}
+}
+
+int yaffs_get_obj_name(struct yaffs_obj *obj, YCHAR *name, int buffer_size)
+{
+	memset(name, 0, buffer_size * sizeof(YCHAR));
+	yaffs_check_obj_details_loaded(obj);
+	if (obj->obj_id == YAFFS_OBJECTID_LOSTNFOUND) {
+		strncpy(name, YAFFS_LOSTNFOUND_NAME, buffer_size - 1);
+	} else if (obj->short_name[0]) {
+		strcpy(name, obj->short_name);
+	} else if (obj->hdr_chunk > 0) {
+		int result;
+		u8 *buffer = yaffs_get_temp_buffer(obj->my_dev);
+
+		struct yaffs_obj_hdr *oh = (struct yaffs_obj_hdr *)buffer;
+
+		memset(buffer, 0, obj->my_dev->data_bytes_per_chunk);
+
+		if (obj->hdr_chunk > 0) {
+			result = yaffs_rd_chunk_tags_nand(obj->my_dev,
+							  obj->hdr_chunk,
+							  buffer, NULL);
+		}
+		yaffs_load_name_from_oh(obj->my_dev, name, oh->name,
+					buffer_size);
+
+		yaffs_release_temp_buffer(obj->my_dev, buffer);
+	}
+
+	yaffs_fix_null_name(obj, name, buffer_size);
+
+	return strnlen(name, YAFFS_MAX_NAME_LENGTH);
+}
+
+loff_t yaffs_get_obj_length(struct yaffs_obj *obj)
+{
+	/* Dereference any hard linking */
+	obj = yaffs_get_equivalent_obj(obj);
+
+	if (obj->variant_type == YAFFS_OBJECT_TYPE_FILE)
+		return obj->variant.file_variant.file_size;
+	if (obj->variant_type == YAFFS_OBJECT_TYPE_SYMLINK) {
+		if (!obj->variant.symlink_variant.alias)
+			return 0;
+		return strnlen(obj->variant.symlink_variant.alias,
+				     YAFFS_MAX_ALIAS_LENGTH);
+	} else {
+		/* Only a directory should drop through to here */
+		return obj->my_dev->data_bytes_per_chunk;
+	}
+}
+
+int yaffs_get_obj_link_count(struct yaffs_obj *obj)
+{
+	int count = 0;
+	struct list_head *i;
+
+	if (!obj->unlinked)
+		count++;	/* the object itself */
+
+	list_for_each(i, &obj->hard_links)
+	    count++;		/* add the hard links; */
+
+	return count;
+}
+
+int yaffs_get_obj_inode(struct yaffs_obj *obj)
+{
+	obj = yaffs_get_equivalent_obj(obj);
+
+	return obj->obj_id;
+}
+
+unsigned yaffs_get_obj_type(struct yaffs_obj *obj)
+{
+	obj = yaffs_get_equivalent_obj(obj);
+
+	switch (obj->variant_type) {
+	case YAFFS_OBJECT_TYPE_FILE:
+		return DT_REG;
+		break;
+	case YAFFS_OBJECT_TYPE_DIRECTORY:
+		return DT_DIR;
+		break;
+	case YAFFS_OBJECT_TYPE_SYMLINK:
+		return DT_LNK;
+		break;
+	case YAFFS_OBJECT_TYPE_HARDLINK:
+		return DT_REG;
+		break;
+	case YAFFS_OBJECT_TYPE_SPECIAL:
+		if (S_ISFIFO(obj->yst_mode))
+			return DT_FIFO;
+		if (S_ISCHR(obj->yst_mode))
+			return DT_CHR;
+		if (S_ISBLK(obj->yst_mode))
+			return DT_BLK;
+		if (S_ISSOCK(obj->yst_mode))
+			return DT_SOCK;
+		return DT_REG;
+		break;
+	default:
+		return DT_REG;
+		break;
+	}
+}
+
+YCHAR *yaffs_get_symlink_alias(struct yaffs_obj *obj)
+{
+	obj = yaffs_get_equivalent_obj(obj);
+	if (obj->variant_type == YAFFS_OBJECT_TYPE_SYMLINK)
+		return yaffs_clone_str(obj->variant.symlink_variant.alias);
+	else
+		return yaffs_clone_str(_Y(""));
+}
+
+/*--------------------------- Initialisation code -------------------------- */
+
+static int yaffs_check_dev_fns(const struct yaffs_dev *dev)
+{
+	/* Common functions, gotta have */
+	if (!dev->param.erase_fn || !dev->param.initialise_flash_fn)
+		return 0;
+
+	/* Can use the "with tags" style interface for yaffs1 or yaffs2 */
+	if (dev->param.write_chunk_tags_fn &&
+	    dev->param.read_chunk_tags_fn &&
+	    !dev->param.write_chunk_fn &&
+	    !dev->param.read_chunk_fn &&
+	    dev->param.bad_block_fn && dev->param.query_block_fn)
+		return 1;
+
+	/* Can use the "spare" style interface for yaffs1 */
+	if (!dev->param.is_yaffs2 &&
+	    !dev->param.write_chunk_tags_fn &&
+	    !dev->param.read_chunk_tags_fn &&
+	    dev->param.write_chunk_fn &&
+	    dev->param.read_chunk_fn &&
+	    !dev->param.bad_block_fn && !dev->param.query_block_fn)
+		return 1;
+
+	return 0;		/* bad */
+}
+
+static int yaffs_create_initial_dir(struct yaffs_dev *dev)
+{
+	/* Initialise the unlinked, deleted, root and lost+found directories */
+	dev->lost_n_found = dev->root_dir = NULL;
+	dev->unlinked_dir = dev->del_dir = NULL;
+	dev->unlinked_dir =
+	    yaffs_create_fake_dir(dev, YAFFS_OBJECTID_UNLINKED, S_IFDIR);
+	dev->del_dir =
+	    yaffs_create_fake_dir(dev, YAFFS_OBJECTID_DELETED, S_IFDIR);
+	dev->root_dir =
+	    yaffs_create_fake_dir(dev, YAFFS_OBJECTID_ROOT,
+				  YAFFS_ROOT_MODE | S_IFDIR);
+	dev->lost_n_found =
+	    yaffs_create_fake_dir(dev, YAFFS_OBJECTID_LOSTNFOUND,
+				  YAFFS_LOSTNFOUND_MODE | S_IFDIR);
+
+	if (dev->lost_n_found && dev->root_dir && dev->unlinked_dir
+	    && dev->del_dir) {
+		yaffs_add_obj_to_dir(dev->root_dir, dev->lost_n_found);
+		return YAFFS_OK;
+	}
+	return YAFFS_FAIL;
+}
+
+int yaffs_guts_initialise(struct yaffs_dev *dev)
+{
+	int init_failed = 0;
+	unsigned x;
+	int bits;
+
+	yaffs_trace(YAFFS_TRACE_TRACING, "yaffs: yaffs_guts_initialise()");
+
+	/* Check stuff that must be set */
+
+	if (!dev) {
+		yaffs_trace(YAFFS_TRACE_ALWAYS,
+			"yaffs: Need a device"
+			);
+		return YAFFS_FAIL;
+	}
+
+	if (dev->is_mounted) {
+		yaffs_trace(YAFFS_TRACE_ALWAYS, "device already mounted");
+		return YAFFS_FAIL;
+	}
+
+	dev->internal_start_block = dev->param.start_block;
+	dev->internal_end_block = dev->param.end_block;
+	dev->block_offset = 0;
+	dev->chunk_offset = 0;
+	dev->n_free_chunks = 0;
+
+	dev->gc_block = 0;
+
+	if (dev->param.start_block == 0) {
+		dev->internal_start_block = dev->param.start_block + 1;
+		dev->internal_end_block = dev->param.end_block + 1;
+		dev->block_offset = 1;
+		dev->chunk_offset = dev->param.chunks_per_block;
+	}
+
+	/* Check geometry parameters. */
+
+	if ((!dev->param.inband_tags && dev->param.is_yaffs2 &&
+		dev->param.total_bytes_per_chunk < 1024) ||
+		(!dev->param.is_yaffs2 &&
+			dev->param.total_bytes_per_chunk < 512) ||
+		(dev->param.inband_tags && !dev->param.is_yaffs2) ||
+		 dev->param.chunks_per_block < 2 ||
+		 dev->param.n_reserved_blocks < 2 ||
+		dev->internal_start_block <= 0 ||
+		dev->internal_end_block <= 0 ||
+		dev->internal_end_block <=
+		(dev->internal_start_block + dev->param.n_reserved_blocks + 2)
+		) {
+		/* otherwise it is too small */
+		yaffs_trace(YAFFS_TRACE_ALWAYS,
+			"NAND geometry problems: chunk size %d, type is yaffs%s, inband_tags %d ",
+			dev->param.total_bytes_per_chunk,
+			dev->param.is_yaffs2 ? "2" : "",
+			dev->param.inband_tags);
+		return YAFFS_FAIL;
+	}
+
+	if (yaffs_init_nand(dev) != YAFFS_OK) {
+		yaffs_trace(YAFFS_TRACE_ALWAYS, "InitialiseNAND failed");
+		return YAFFS_FAIL;
+	}
+
+	/* Sort out space for inband tags, if required */
+	if (dev->param.inband_tags)
+		dev->data_bytes_per_chunk =
+		    dev->param.total_bytes_per_chunk -
+		    sizeof(struct yaffs_packed_tags2_tags_only);
+	else
+		dev->data_bytes_per_chunk = dev->param.total_bytes_per_chunk;
+
+	/* Got the right mix of functions? */
+	if (!yaffs_check_dev_fns(dev)) {
+		/* Function missing */
+		yaffs_trace(YAFFS_TRACE_ALWAYS,
+			"device function(s) missing or wrong");
+
+		return YAFFS_FAIL;
+	}
+
+	/* Finished with most checks. Further checks happen later on too. */
+
+	dev->is_mounted = 1;
+
+	/* OK now calculate a few things for the device */
+
+	/*
+	 *  Calculate all the chunk size manipulation numbers:
+	 */
+	x = dev->data_bytes_per_chunk;
+	/* We always use dev->chunk_shift and dev->chunk_div */
+	dev->chunk_shift = calc_shifts(x);
+	x >>= dev->chunk_shift;
+	dev->chunk_div = x;
+	/* We only use chunk mask if chunk_div is 1 */
+	dev->chunk_mask = (1 << dev->chunk_shift) - 1;
+
+	/*
+	 * Calculate chunk_grp_bits.
+	 * We need to find the next power of 2 > than internal_end_block
+	 */
+
+	x = dev->param.chunks_per_block * (dev->internal_end_block + 1);
+
+	bits = calc_shifts_ceiling(x);
+
+	/* Set up tnode width if wide tnodes are enabled. */
+	if (!dev->param.wide_tnodes_disabled) {
+		/* bits must be even so that we end up with 32-bit words */
+		if (bits & 1)
+			bits++;
+		if (bits < 16)
+			dev->tnode_width = 16;
+		else
+			dev->tnode_width = bits;
+	} else {
+		dev->tnode_width = 16;
+	}
+
+	dev->tnode_mask = (1 << dev->tnode_width) - 1;
+
+	/* Level0 Tnodes are 16 bits or wider (if wide tnodes are enabled),
+	 * so if the bitwidth of the
+	 * chunk range we're using is greater than 16 we need
+	 * to figure out chunk shift and chunk_grp_size
+	 */
+
+	if (bits <= dev->tnode_width)
+		dev->chunk_grp_bits = 0;
+	else
+		dev->chunk_grp_bits = bits - dev->tnode_width;
+
+	dev->tnode_size = (dev->tnode_width * YAFFS_NTNODES_LEVEL0) / 8;
+	if (dev->tnode_size < sizeof(struct yaffs_tnode))
+		dev->tnode_size = sizeof(struct yaffs_tnode);
+
+	dev->chunk_grp_size = 1 << dev->chunk_grp_bits;
+
+	if (dev->param.chunks_per_block < dev->chunk_grp_size) {
+		/* We have a problem because the soft delete won't work if
+		 * the chunk group size > chunks per block.
+		 * This can be remedied by using larger "virtual blocks".
+		 */
+		yaffs_trace(YAFFS_TRACE_ALWAYS, "chunk group too large");
+
+		return YAFFS_FAIL;
+	}
+
+	/* Finished verifying the device, continue with initialisation */
+
+	/* More device initialisation */
+	dev->all_gcs = 0;
+	dev->passive_gc_count = 0;
+	dev->oldest_dirty_gc_count = 0;
+	dev->bg_gcs = 0;
+	dev->gc_block_finder = 0;
+	dev->buffered_block = -1;
+	dev->doing_buffered_block_rewrite = 0;
+	dev->n_deleted_files = 0;
+	dev->n_bg_deletions = 0;
+	dev->n_unlinked_files = 0;
+	dev->n_ecc_fixed = 0;
+	dev->n_ecc_unfixed = 0;
+	dev->n_tags_ecc_fixed = 0;
+	dev->n_tags_ecc_unfixed = 0;
+	dev->n_erase_failures = 0;
+	dev->n_erased_blocks = 0;
+	dev->gc_disable = 0;
+	dev->has_pending_prioritised_gc = 1;
+		/* Assume the worst for now, will get fixed on first GC */
+	INIT_LIST_HEAD(&dev->dirty_dirs);
+	dev->oldest_dirty_seq = 0;
+	dev->oldest_dirty_block = 0;
+
+	/* Initialise temporary buffers and caches. */
+	if (!yaffs_init_tmp_buffers(dev))
+		init_failed = 1;
+
+	dev->cache = NULL;
+	dev->gc_cleanup_list = NULL;
+
+	if (!init_failed && dev->param.n_caches > 0) {
+		int i;
+		void *buf;
+		int cache_bytes =
+		    dev->param.n_caches * sizeof(struct yaffs_cache);
+
+		if (dev->param.n_caches > YAFFS_MAX_SHORT_OP_CACHES)
+			dev->param.n_caches = YAFFS_MAX_SHORT_OP_CACHES;
+
+		dev->cache = kmalloc(cache_bytes, GFP_NOFS);
+
+		buf = (u8 *) dev->cache;
+
+		if (dev->cache)
+			memset(dev->cache, 0, cache_bytes);
+
+		for (i = 0; i < dev->param.n_caches && buf; i++) {
+			dev->cache[i].object = NULL;
+			dev->cache[i].last_use = 0;
+			dev->cache[i].dirty = 0;
+			dev->cache[i].data = buf =
+			    kmalloc(dev->param.total_bytes_per_chunk, GFP_NOFS);
+		}
+		if (!buf)
+			init_failed = 1;
+
+		dev->cache_last_use = 0;
+	}
+
+	dev->cache_hits = 0;
+
+	if (!init_failed) {
+		dev->gc_cleanup_list =
+		    kmalloc(dev->param.chunks_per_block * sizeof(u32),
+					GFP_NOFS);
+		if (!dev->gc_cleanup_list)
+			init_failed = 1;
+	}
+
+	if (dev->param.is_yaffs2)
+		dev->param.use_header_file_size = 1;
+
+	if (!init_failed && !yaffs_init_blocks(dev))
+		init_failed = 1;
+
+	yaffs_init_tnodes_and_objs(dev);
+
+	if (!init_failed && !yaffs_create_initial_dir(dev))
+		init_failed = 1;
+
+	if (!init_failed && dev->param.is_yaffs2 &&
+		!dev->param.disable_summary &&
+		!yaffs_summary_init(dev))
+		init_failed = 1;
+
+	if (!init_failed) {
+		/* Now scan the flash. */
+		if (dev->param.is_yaffs2) {
+			if (yaffs2_checkpt_restore(dev)) {
+				yaffs_check_obj_details_loaded(dev->root_dir);
+				yaffs_trace(YAFFS_TRACE_CHECKPOINT |
+					YAFFS_TRACE_MOUNT,
+					"yaffs: restored from checkpoint"
+					);
+			} else {
+
+				/* Clean up the mess caused by an aborted
+				 * checkpoint load then scan backwards.
+				 */
+				yaffs_deinit_blocks(dev);
+
+				yaffs_deinit_tnodes_and_objs(dev);
+
+				dev->n_erased_blocks = 0;
+				dev->n_free_chunks = 0;
+				dev->alloc_block = -1;
+				dev->alloc_page = -1;
+				dev->n_deleted_files = 0;
+				dev->n_unlinked_files = 0;
+				dev->n_bg_deletions = 0;
+
+				if (!init_failed && !yaffs_init_blocks(dev))
+					init_failed = 1;
+
+				yaffs_init_tnodes_and_objs(dev);
+
+				if (!init_failed
+				    && !yaffs_create_initial_dir(dev))
+					init_failed = 1;
+
+				if (!init_failed && !yaffs2_scan_backwards(dev))
+					init_failed = 1;
+			}
+		} else if (!yaffs1_scan(dev)) {
+			init_failed = 1;
+		}
+
+		yaffs_strip_deleted_objs(dev);
+		yaffs_fix_hanging_objs(dev);
+		if (dev->param.empty_lost_n_found)
+			yaffs_empty_l_n_f(dev);
+	}
+
+	if (init_failed) {
+		/* Clean up the mess */
+		yaffs_trace(YAFFS_TRACE_TRACING,
+		  "yaffs: yaffs_guts_initialise() aborted.");
+
+		yaffs_deinitialise(dev);
+		return YAFFS_FAIL;
+	}
+
+	/* Zero out stats */
+	dev->n_page_reads = 0;
+	dev->n_page_writes = 0;
+	dev->n_erasures = 0;
+	dev->n_gc_copies = 0;
+	dev->n_retried_writes = 0;
+
+	dev->n_retired_blocks = 0;
+
+	yaffs_verify_free_chunks(dev);
+	yaffs_verify_blocks(dev);
+
+	/* Clean up any aborted checkpoint data */
+	if (!dev->is_checkpointed && dev->blocks_in_checkpt > 0)
+		yaffs2_checkpt_invalidate(dev);
+
+	yaffs_trace(YAFFS_TRACE_TRACING,
+	  "yaffs: yaffs_guts_initialise() done.");
+	return YAFFS_OK;
+}
+
+void yaffs_deinitialise(struct yaffs_dev *dev)
+{
+	if (dev->is_mounted) {
+		int i;
+
+		yaffs_deinit_blocks(dev);
+		yaffs_deinit_tnodes_and_objs(dev);
+		yaffs_summary_deinit(dev);
+
+		if (dev->param.n_caches > 0 && dev->cache) {
+
+			for (i = 0; i < dev->param.n_caches; i++) {
+				kfree(dev->cache[i].data);
+				dev->cache[i].data = NULL;
+			}
+
+			kfree(dev->cache);
+			dev->cache = NULL;
+		}
+
+		kfree(dev->gc_cleanup_list);
+
+		for (i = 0; i < YAFFS_N_TEMP_BUFFERS; i++)
+			kfree(dev->temp_buffer[i].buffer);
+
+		dev->is_mounted = 0;
+
+		if (dev->param.deinitialise_flash_fn)
+			dev->param.deinitialise_flash_fn(dev);
+	}
+}
+
+int yaffs_count_free_chunks(struct yaffs_dev *dev)
+{
+	int n_free = 0;
+	int b;
+	struct yaffs_block_info *blk;
+
+	blk = dev->block_info;
+	for (b = dev->internal_start_block; b <= dev->internal_end_block; b++) {
+		switch (blk->block_state) {
+		case YAFFS_BLOCK_STATE_EMPTY:
+		case YAFFS_BLOCK_STATE_ALLOCATING:
+		case YAFFS_BLOCK_STATE_COLLECTING:
+		case YAFFS_BLOCK_STATE_FULL:
+			n_free +=
+			    (dev->param.chunks_per_block - blk->pages_in_use +
+			     blk->soft_del_pages);
+			break;
+		default:
+			break;
+		}
+		blk++;
+	}
+	return n_free;
+}
+
+int yaffs_get_n_free_chunks(struct yaffs_dev *dev)
+{
+	/* This is what we report to the outside world */
+	int n_free;
+	int n_dirty_caches;
+	int blocks_for_checkpt;
+	int i;
+
+	n_free = dev->n_free_chunks;
+	n_free += dev->n_deleted_files;
+
+	/* Now count and subtract the number of dirty chunks in the cache. */
+
+	for (n_dirty_caches = 0, i = 0; i < dev->param.n_caches; i++) {
+		if (dev->cache[i].dirty)
+			n_dirty_caches++;
+	}
+
+	n_free -= n_dirty_caches;
+
+	n_free -=
+	    ((dev->param.n_reserved_blocks + 1) * dev->param.chunks_per_block);
+
+	/* Now figure checkpoint space and report that... */
+	blocks_for_checkpt = yaffs_calc_checkpt_blocks_required(dev);
+
+	n_free -= (blocks_for_checkpt * dev->param.chunks_per_block);
+
+	if (n_free < 0)
+		n_free = 0;
+
+	return n_free;
+}
+
+
+int yaffs_format_dev(struct yaffs_dev *dev)
+{
+	int i;
+	enum yaffs_block_state state;
+	u32 dummy;
+
+	if(dev->is_mounted)
+		return YAFFS_FAIL;
+
+	/*
+	* The runtime variables might not have been set up,
+	* so set up what we need.
+	*/
+	dev->internal_start_block = dev->param.start_block;
+	dev->internal_end_block = dev->param.end_block;
+	dev->block_offset = 0;
+	dev->chunk_offset = 0;
+
+	if (dev->param.start_block == 0) {
+		dev->internal_start_block = dev->param.start_block + 1;
+		dev->internal_end_block = dev->param.end_block + 1;
+		dev->block_offset = 1;
+		dev->chunk_offset = dev->param.chunks_per_block;
+	}
+
+	for (i = dev->internal_start_block; i <= dev->internal_end_block; i++) {
+		yaffs_query_init_block_state(dev, i, &state, &dummy);
+		if (state != YAFFS_BLOCK_STATE_DEAD)
+			yaffs_erase_block(dev, i);
+	}
+
+	return YAFFS_OK;
+}
+
+
+/*
+ * Marshalling functions to get loff_t file sizes into and out of
+ * object headers.
+ */
+void yaffs_oh_size_load(struct yaffs_obj_hdr *oh, loff_t fsize)
+{
+	oh->file_size_low = (fsize & 0xFFFFFFFF);
+	oh->file_size_high = ((fsize >> 32) & 0xFFFFFFFF);
+}
+
+loff_t yaffs_oh_to_size(struct yaffs_obj_hdr *oh)
+{
+	loff_t retval;
+
+	if (sizeof(loff_t) >= 8 && ~(oh->file_size_high))
+		retval = (((loff_t) oh->file_size_high) << 32) |
+			(((loff_t) oh->file_size_low) & 0xFFFFFFFF);
+	else
+		retval = (loff_t) oh->file_size_low;
+
+	return retval;
+}
diff --git a/linux-bsp/asm-study/yaffs2/yaffs2/yaffs_guts.h b/linux-bsp/asm-study/yaffs2/yaffs2/yaffs_guts.h
new file mode 100644
index 0000000..0e334bd
--- /dev/null
+++ b/linux-bsp/asm-study/yaffs2/yaffs2/yaffs_guts.h
@@ -0,0 +1,977 @@
+/*
+ * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
+ *
+ * Copyright (C) 2002-2011 Aleph One Ltd.
+ *   for Toby Churchill Ltd and Brightstar Engineering
+ *
+ * Created by Charles Manning <charles@aleph1.co.uk>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 2.1 as
+ * published by the Free Software Foundation.
+ *
+ * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
+ */
+
+#ifndef __YAFFS_GUTS_H__
+#define __YAFFS_GUTS_H__
+
+#include "yportenv.h"
+
+#define YAFFS_OK	1
+#define YAFFS_FAIL  0
+
+/* Give us a  Y=0x59,
+ * Give us an A=0x41,
+ * Give us an FF=0xff
+ * Give us an S=0x53
+ * And what have we got...
+ */
+#define YAFFS_MAGIC			0x5941ff53
+
+/*
+ * Tnodes form a tree with the tnodes in "levels"
+ * Levels greater than 0 hold 8 slots which point to other tnodes.
+ * Those at level 0 hold 16 slots which point to chunks in NAND.
+ *
+ * A maximum level of 8 thust supports files of size up to:
+ *
+ * 2^(3*MAX_LEVEL+4)
+ *
+ * Thus a max level of 8 supports files with up to 2^^28 chunks which gives
+ * a maximum file size of arounf 51Gbytees with 2k chunks.
+ */
+#define YAFFS_NTNODES_LEVEL0		16
+#define YAFFS_TNODES_LEVEL0_BITS	4
+#define YAFFS_TNODES_LEVEL0_MASK	0xf
+
+#define YAFFS_NTNODES_INTERNAL		(YAFFS_NTNODES_LEVEL0 / 2)
+#define YAFFS_TNODES_INTERNAL_BITS	(YAFFS_TNODES_LEVEL0_BITS - 1)
+#define YAFFS_TNODES_INTERNAL_MASK	0x7
+#define YAFFS_TNODES_MAX_LEVEL		8
+#define YAFFS_TNODES_MAX_BITS		(YAFFS_TNODES_LEVEL0_BITS + \
+					YAFFS_TNODES_INTERNAL_BITS * \
+					YAFFS_TNODES_MAX_LEVEL)
+#define YAFFS_MAX_CHUNK_ID		((1 << YAFFS_TNODES_MAX_BITS) - 1)
+
+#define YAFFS_MAX_FILE_SIZE_32		0x7fffffff
+
+/* Constants for YAFFS1 mode */
+#define YAFFS_BYTES_PER_SPARE		16
+#define YAFFS_BYTES_PER_CHUNK		512
+#define YAFFS_CHUNK_SIZE_SHIFT		9
+#define YAFFS_CHUNKS_PER_BLOCK		32
+#define YAFFS_BYTES_PER_BLOCK	(YAFFS_CHUNKS_PER_BLOCK*YAFFS_BYTES_PER_CHUNK)
+
+#define YAFFS_MIN_YAFFS2_CHUNK_SIZE	1024
+#define YAFFS_MIN_YAFFS2_SPARE_SIZE	32
+
+
+
+#define YAFFS_ALLOCATION_NOBJECTS	100
+#define YAFFS_ALLOCATION_NTNODES	100
+#define YAFFS_ALLOCATION_NLINKS		100
+
+#define YAFFS_NOBJECT_BUCKETS		256
+
+#define YAFFS_OBJECT_SPACE		0x40000
+#define YAFFS_MAX_OBJECT_ID		(YAFFS_OBJECT_SPACE - 1)
+
+/* Binary data version stamps */
+#define YAFFS_SUMMARY_VERSION		1
+#define YAFFS_CHECKPOINT_VERSION	7
+
+#ifdef CONFIG_YAFFS_UNICODE
+#define YAFFS_MAX_NAME_LENGTH		127
+#define YAFFS_MAX_ALIAS_LENGTH		79
+#else
+#define YAFFS_MAX_NAME_LENGTH		255
+#define YAFFS_MAX_ALIAS_LENGTH		159
+#endif
+
+#define YAFFS_SHORT_NAME_LENGTH		15
+
+/* Some special object ids for pseudo objects */
+#define YAFFS_OBJECTID_ROOT		1
+#define YAFFS_OBJECTID_LOSTNFOUND	2
+#define YAFFS_OBJECTID_UNLINKED		3
+#define YAFFS_OBJECTID_DELETED		4
+
+/* Fake object Id for summary data */
+#define YAFFS_OBJECTID_SUMMARY		0x10
+
+/* Pseudo object ids for checkpointing */
+#define YAFFS_OBJECTID_CHECKPOINT_DATA	0x20
+#define YAFFS_SEQUENCE_CHECKPOINT_DATA	0x21
+
+#define YAFFS_MAX_SHORT_OP_CACHES	20
+
+#define YAFFS_N_TEMP_BUFFERS		6
+
+/* We limit the number attempts at sucessfully saving a chunk of data.
+ * Small-page devices have 32 pages per block; large-page devices have 64.
+ * Default to something in the order of 5 to 10 blocks worth of chunks.
+ */
+#define YAFFS_WR_ATTEMPTS		(5*64)
+
+/* Sequence numbers are used in YAFFS2 to determine block allocation order.
+ * The range is limited slightly to help distinguish bad numbers from good.
+ * This also allows us to perhaps in the future use special numbers for
+ * special purposes.
+ * EFFFFF00 allows the allocation of 8 blocks/second (~1Mbytes) for 15 years,
+ * and is a larger number than the lifetime of a 2GB device.
+ */
+#define YAFFS_LOWEST_SEQUENCE_NUMBER	0x00001000
+#define YAFFS_HIGHEST_SEQUENCE_NUMBER	0xefffff00
+
+/* Special sequence number for bad block that failed to be marked bad */
+#define YAFFS_SEQUENCE_BAD_BLOCK	0xffff0000
+
+/* ChunkCache is used for short read/write operations.*/
+struct yaffs_cache {
+	struct yaffs_obj *object;
+	int chunk_id;
+	int last_use;
+	int dirty;
+	int n_bytes;		/* Only valid if the cache is dirty */
+	int locked;		/* Can't push out or flush while locked. */
+	u8 *data;
+};
+
+/* yaffs1 tags structures in RAM
+ * NB This uses bitfield. Bitfields should not straddle a u32 boundary
+ * otherwise the structure size will get blown out.
+ */
+
+struct yaffs_tags {
+	unsigned chunk_id:20;
+	unsigned serial_number:2;
+	unsigned n_bytes_lsb:10;
+	unsigned obj_id:18;
+	unsigned ecc:12;
+	unsigned n_bytes_msb:2;
+};
+
+union yaffs_tags_union {
+	struct yaffs_tags as_tags;
+	u8 as_bytes[8];
+};
+
+
+/* Stuff used for extended tags in YAFFS2 */
+
+enum yaffs_ecc_result {
+	YAFFS_ECC_RESULT_UNKNOWN,
+	YAFFS_ECC_RESULT_NO_ERROR,
+	YAFFS_ECC_RESULT_FIXED,
+	YAFFS_ECC_RESULT_UNFIXED
+};
+
+enum yaffs_obj_type {
+	YAFFS_OBJECT_TYPE_UNKNOWN,
+	YAFFS_OBJECT_TYPE_FILE,
+	YAFFS_OBJECT_TYPE_SYMLINK,
+	YAFFS_OBJECT_TYPE_DIRECTORY,
+	YAFFS_OBJECT_TYPE_HARDLINK,
+	YAFFS_OBJECT_TYPE_SPECIAL
+};
+
+#define YAFFS_OBJECT_TYPE_MAX YAFFS_OBJECT_TYPE_SPECIAL
+
+struct yaffs_ext_tags {
+	unsigned chunk_used;	/*  Status of the chunk: used or unused */
+	unsigned obj_id;	/* If 0 this is not used */
+	unsigned chunk_id;	/* If 0 this is a header, else a data chunk */
+	unsigned n_bytes;	/* Only valid for data chunks */
+
+	/* The following stuff only has meaning when we read */
+	enum yaffs_ecc_result ecc_result;
+	unsigned block_bad;
+
+	/* YAFFS 1 stuff */
+	unsigned is_deleted;	/* The chunk is marked deleted */
+	unsigned serial_number;	/* Yaffs1 2-bit serial number */
+
+	/* YAFFS2 stuff */
+	unsigned seq_number;	/* The sequence number of this block */
+
+	/* Extra info if this is an object header (YAFFS2 only) */
+
+	unsigned extra_available;	/* Extra info available if not zero */
+	unsigned extra_parent_id;	/* The parent object */
+	unsigned extra_is_shrink;	/* Is it a shrink header? */
+	unsigned extra_shadows;	/* Does this shadow another object? */
+
+	enum yaffs_obj_type extra_obj_type;	/* What object type? */
+
+	loff_t extra_file_size;		/* Length if it is a file */
+	unsigned extra_equiv_id;	/* Equivalent object for a hard link */
+};
+
+/* Spare structure for YAFFS1 */
+struct yaffs_spare {
+	u8 tb0;
+	u8 tb1;
+	u8 tb2;
+	u8 tb3;
+	u8 page_status;		/* set to 0 to delete the chunk */
+	u8 block_status;
+	u8 tb4;
+	u8 tb5;
+	u8 ecc1[3];
+	u8 tb6;
+	u8 tb7;
+	u8 ecc2[3];
+};
+
+/*Special structure for passing through to mtd */
+struct yaffs_nand_spare {
+	struct yaffs_spare spare;
+	int eccres1;
+	int eccres2;
+};
+
+/* Block data in RAM */
+
+enum yaffs_block_state {
+	YAFFS_BLOCK_STATE_UNKNOWN = 0,
+
+	YAFFS_BLOCK_STATE_SCANNING,
+	/* Being scanned */
+
+	YAFFS_BLOCK_STATE_NEEDS_SCAN,
+	/* The block might have something on it (ie it is allocating or full,
+	 * perhaps empty) but it needs to be scanned to determine its true
+	 * state.
+	 * This state is only valid during scanning.
+	 * NB We tolerate empty because the pre-scanner might be incapable of
+	 * deciding
+	 * However, if this state is returned on a YAFFS2 device,
+	 * then we expect a sequence number
+	 */
+
+	YAFFS_BLOCK_STATE_EMPTY,
+	/* This block is empty */
+
+	YAFFS_BLOCK_STATE_ALLOCATING,
+	/* This block is partially allocated.
+	 * At least one page holds valid data.
+	 * This is the one currently being used for page
+	 * allocation. Should never be more than one of these.
+	 * If a block is only partially allocated at mount it is treated as
+	 * full.
+	 */
+
+	YAFFS_BLOCK_STATE_FULL,
+	/* All the pages in this block have been allocated.
+	 * If a block was only partially allocated when mounted we treat
+	 * it as fully allocated.
+	 */
+
+	YAFFS_BLOCK_STATE_DIRTY,
+	/* The block was full and now all chunks have been deleted.
+	 * Erase me, reuse me.
+	 */
+
+	YAFFS_BLOCK_STATE_CHECKPOINT,
+	/* This block is assigned to holding checkpoint data. */
+
+	YAFFS_BLOCK_STATE_COLLECTING,
+	/* This block is being garbage collected */
+
+	YAFFS_BLOCK_STATE_DEAD
+	    /* This block has failed and is not in use */
+};
+
+#define	YAFFS_NUMBER_OF_BLOCK_STATES (YAFFS_BLOCK_STATE_DEAD + 1)
+
+struct yaffs_block_info {
+
+	int soft_del_pages:10;	/* number of soft deleted pages */
+	int pages_in_use:10;	/* number of pages in use */
+	unsigned block_state:4;	/* One of the above block states. */
+				/* NB use unsigned because enum is sometimes
+				 * an int */
+	u32 needs_retiring:1;	/* Data has failed on this block, */
+				/*need to get valid data off and retire*/
+	u32 skip_erased_check:1;/* Skip the erased check on this block */
+	u32 gc_prioritise:1;	/* An ECC check or blank check has failed.
+				   Block should be prioritised for GC */
+	u32 chunk_error_strikes:3;	/* How many times we've had ecc etc
+				failures on this block and tried to reuse it */
+	u32 has_summary:1;	/* The block has a summary */
+
+	u32 has_shrink_hdr:1;	/* This block has at least one shrink header */
+	u32 seq_number;		/* block sequence number for yaffs2 */
+
+};
+
+/* -------------------------- Object structure -------------------------------*/
+/* This is the object structure as stored on NAND */
+
+struct yaffs_obj_hdr {
+	enum yaffs_obj_type type;
+
+	/* Apply to everything  */
+	int parent_obj_id;
+	u16 sum_no_longer_used;	/* checksum of name. No longer used */
+	YCHAR name[YAFFS_MAX_NAME_LENGTH + 1];
+
+	/* The following apply to all object types except for hard links */
+	u32 yst_mode;		/* protection */
+
+	u32 yst_uid;
+	u32 yst_gid;
+	u32 yst_atime;
+	u32 yst_mtime;
+	u32 yst_ctime;
+
+	/* File size  applies to files only */
+	u32 file_size_low;
+
+	/* Equivalent object id applies to hard links only. */
+	int equiv_id;
+
+	/* Alias is for symlinks only. */
+	YCHAR alias[YAFFS_MAX_ALIAS_LENGTH + 1];
+
+	u32 yst_rdev;	/* stuff for block and char devices (major/min) */
+
+	u32 win_ctime[2];
+	u32 win_atime[2];
+	u32 win_mtime[2];
+
+	u32 inband_shadowed_obj_id;
+	u32 inband_is_shrink;
+
+	u32 file_size_high;
+	u32 reserved[1];
+	int shadows_obj;	/* This object header shadows the
+				specified object if > 0 */
+
+	/* is_shrink applies to object headers written when wemake a hole. */
+	u32 is_shrink;
+
+};
+
+/*--------------------------- Tnode -------------------------- */
+
+struct yaffs_tnode {
+	struct yaffs_tnode *internal[YAFFS_NTNODES_INTERNAL];
+};
+
+/*------------------------  Object -----------------------------*/
+/* An object can be one of:
+ * - a directory (no data, has children links
+ * - a regular file (data.... not prunes :->).
+ * - a symlink [symbolic link] (the alias).
+ * - a hard link
+ */
+
+struct yaffs_file_var {
+	loff_t file_size;
+	loff_t scanned_size;
+	loff_t shrink_size;
+	int top_level;
+	struct yaffs_tnode *top;
+};
+
+struct yaffs_dir_var {
+	struct list_head children;	/* list of child links */
+	struct list_head dirty;	/* Entry for list of dirty directories */
+};
+
+struct yaffs_symlink_var {
+	YCHAR *alias;
+};
+
+struct yaffs_hardlink_var {
+	struct yaffs_obj *equiv_obj;
+	u32 equiv_id;
+};
+
+union yaffs_obj_var {
+	struct yaffs_file_var file_variant;
+	struct yaffs_dir_var dir_variant;
+	struct yaffs_symlink_var symlink_variant;
+	struct yaffs_hardlink_var hardlink_variant;
+};
+
+struct yaffs_obj {
+	u8 deleted:1;		/* This should only apply to unlinked files. */
+	u8 soft_del:1;		/* it has also been soft deleted */
+	u8 unlinked:1;		/* An unlinked file.*/
+	u8 fake:1;		/* A fake object has no presence on NAND. */
+	u8 rename_allowed:1;	/* Some objects cannot be renamed. */
+	u8 unlink_allowed:1;
+	u8 dirty:1;		/* the object needs to be written to flash */
+	u8 valid:1;		/* When the file system is being loaded up, this
+				 * object might be created before the data
+				 * is available
+				 * ie. file data chunks encountered before
+				* the header.
+				 */
+	u8 lazy_loaded:1;	/* This object has been lazy loaded and
+				 * is missing some detail */
+
+	u8 defered_free:1;	/* Object is removed from NAND, but is
+				 * still in the inode cache.
+				 * Free of object is defered.
+				 * until the inode is released.
+				 */
+	u8 being_created:1;	/* This object is still being created
+				 * so skip some verification checks. */
+	u8 is_shadowed:1;	/* This object is shadowed on the way
+				 * to being renamed. */
+
+	u8 xattr_known:1;	/* We know if this has object has xattribs
+				 * or not. */
+	u8 has_xattr:1;		/* This object has xattribs.
+				 * Only valid if xattr_known. */
+
+	u8 serial;		/* serial number of chunk in NAND.*/
+	u16 sum;		/* sum of the name to speed searching */
+
+	struct yaffs_dev *my_dev;	/* The device I'm on */
+
+	struct list_head hash_link;	/* list of objects in hash bucket */
+
+	struct list_head hard_links;	/* hard linked object chain*/
+
+	/* directory structure stuff */
+	/* also used for linking up the free list */
+	struct yaffs_obj *parent;
+	struct list_head siblings;
+
+	/* Where's my object header in NAND? */
+	int hdr_chunk;
+
+	int n_data_chunks;	/* Number of data chunks for this file. */
+
+	u32 obj_id;		/* the object id value */
+
+	u32 yst_mode;
+
+	YCHAR short_name[YAFFS_SHORT_NAME_LENGTH + 1];
+
+#ifdef CONFIG_YAFFS_WINCE
+	u32 win_ctime[2];
+	u32 win_mtime[2];
+	u32 win_atime[2];
+#else
+	u32 yst_uid;
+	u32 yst_gid;
+	u32 yst_atime;
+	u32 yst_mtime;
+	u32 yst_ctime;
+#endif
+
+	u32 yst_rdev;
+
+	void *my_inode;
+
+	enum yaffs_obj_type variant_type;
+
+	union yaffs_obj_var variant;
+
+};
+
+struct yaffs_obj_bucket {
+	struct list_head list;
+	int count;
+};
+
+/* yaffs_checkpt_obj holds the definition of an object as dumped
+ * by checkpointing.
+ */
+
+struct yaffs_checkpt_obj {
+	int struct_type;
+	u32 obj_id;
+	u32 parent_id;
+	int hdr_chunk;
+	enum yaffs_obj_type variant_type:3;
+	u8 deleted:1;
+	u8 soft_del:1;
+	u8 unlinked:1;
+	u8 fake:1;
+	u8 rename_allowed:1;
+	u8 unlink_allowed:1;
+	u8 serial;
+	int n_data_chunks;
+	loff_t size_or_equiv_obj;
+};
+
+/*--------------------- Temporary buffers ----------------
+ *
+ * These are chunk-sized working buffers. Each device has a few.
+ */
+
+struct yaffs_buffer {
+	u8 *buffer;
+	int in_use;
+};
+
+/*----------------- Device ---------------------------------*/
+
+struct yaffs_param {
+	const YCHAR *name;
+
+	/*
+	 * Entry parameters set up way early. Yaffs sets up the rest.
+	 * The structure should be zeroed out before use so that unused
+	 * and defualt values are zero.
+	 */
+
+	int inband_tags;	/* Use unband tags */
+	u32 total_bytes_per_chunk;	/* Should be >= 512, does not need to
+					 be a power of 2 */
+	int chunks_per_block;	/* does not need to be a power of 2 */
+	int spare_bytes_per_chunk;	/* spare area size */
+	int start_block;	/* Start block we're allowed to use */
+	int end_block;		/* End block we're allowed to use */
+	int n_reserved_blocks;	/* Tuneable so that we can reduce
+				 * reserved blocks on NOR and RAM. */
+
+	int n_caches;		/* If <= 0, then short op caching is disabled,
+				 * else the number of short op caches.
+				 */
+	int use_nand_ecc;	/* Flag to decide whether or not to use
+				 * NAND driver ECC on data (yaffs1) */
+	int tags_9bytes;	/* Use 9 byte tags */
+	int no_tags_ecc;	/* Flag to decide whether or not to do ECC
+				 * on packed tags (yaffs2) */
+
+	int is_yaffs2;		/* Use yaffs2 mode on this device */
+
+	int empty_lost_n_found;	/* Auto-empty lost+found directory on mount */
+
+	int refresh_period;	/* How often to check for a block refresh */
+
+	/* Checkpoint control. Can be set before or after initialisation */
+	u8 skip_checkpt_rd;
+	u8 skip_checkpt_wr;
+
+	int enable_xattr;	/* Enable xattribs */
+
+	/* NAND access functions (Must be set before calling YAFFS) */
+
+	int (*write_chunk_fn) (struct yaffs_dev *dev,
+			       int nand_chunk, const u8 *data,
+			       const struct yaffs_spare *spare);
+	int (*read_chunk_fn) (struct yaffs_dev *dev,
+			      int nand_chunk, u8 *data,
+			      struct yaffs_spare *spare);
+	int (*erase_fn) (struct yaffs_dev *dev, int flash_block);
+	int (*initialise_flash_fn) (struct yaffs_dev *dev);
+	int (*deinitialise_flash_fn) (struct yaffs_dev *dev);
+
+	/* yaffs2 mode functions */
+	int (*write_chunk_tags_fn) (struct yaffs_dev *dev,
+				    int nand_chunk, const u8 *data,
+				    const struct yaffs_ext_tags *tags);
+	int (*read_chunk_tags_fn) (struct yaffs_dev *dev,
+				   int nand_chunk, u8 *data,
+				   struct yaffs_ext_tags *tags);
+	int (*bad_block_fn) (struct yaffs_dev *dev, int block_no);
+	int (*query_block_fn) (struct yaffs_dev *dev, int block_no,
+			       enum yaffs_block_state *state,
+			       u32 *seq_number);
+
+	/* The remove_obj_fn function must be supplied by OS flavours that
+	 * need it.
+	 * yaffs direct uses it to implement the faster readdir.
+	 * Linux uses it to protect the directory during unlocking.
+	 */
+	void (*remove_obj_fn) (struct yaffs_obj *obj);
+
+	/* Callback to mark the superblock dirty */
+	void (*sb_dirty_fn) (struct yaffs_dev *dev);
+
+	/*  Callback to control garbage collection. */
+	unsigned (*gc_control) (struct yaffs_dev *dev);
+
+	/* Debug control flags. Don't use unless you know what you're doing */
+	int use_header_file_size;	/* Flag to determine if we should use
+					 * file sizes from the header */
+	int disable_lazy_load;	/* Disable lazy loading on this device */
+	int wide_tnodes_disabled;	/* Set to disable wide tnodes */
+	int disable_soft_del;	/* yaffs 1 only: Set to disable the use of
+				 * softdeletion. */
+
+	int defered_dir_update;	/* Set to defer directory updates */
+
+#ifdef CONFIG_YAFFS_AUTO_UNICODE
+	int auto_unicode;
+#endif
+	int always_check_erased;	/* Force chunk erased check always on */
+
+	int disable_summary;
+
+	int max_objects;	/*
+				 * Set to limit the number of objects created.
+				 * 0 = no limit.
+				*/
+};
+
+struct yaffs_dev {
+	struct yaffs_param param;
+
+	/* Context storage. Holds extra OS specific data for this device */
+
+	void *os_context;
+	void *driver_context;
+
+	struct list_head dev_list;
+
+	/* Runtime parameters. Set up by YAFFS. */
+	int data_bytes_per_chunk;
+
+	/* Non-wide tnode stuff */
+	u16 chunk_grp_bits;	/* Number of bits that need to be resolved if
+				 * the tnodes are not wide enough.
+				 */
+	u16 chunk_grp_size;	/* == 2^^chunk_grp_bits */
+
+	/* Stuff to support wide tnodes */
+	u32 tnode_width;
+	u32 tnode_mask;
+	u32 tnode_size;
+
+	/* Stuff for figuring out file offset to chunk conversions */
+	u32 chunk_shift;	/* Shift value */
+	u32 chunk_div;		/* Divisor after shifting: 1 for 2^n sizes */
+	u32 chunk_mask;		/* Mask to use for power-of-2 case */
+
+	int is_mounted;
+	int read_only;
+	int is_checkpointed;
+
+	/* Stuff to support block offsetting to support start block zero */
+	int internal_start_block;
+	int internal_end_block;
+	int block_offset;
+	int chunk_offset;
+
+	/* Runtime checkpointing stuff */
+	int checkpt_page_seq;	/* running sequence number of checkpt pages */
+	int checkpt_byte_count;
+	int checkpt_byte_offs;
+	u8 *checkpt_buffer;
+	int checkpt_open_write;
+	int blocks_in_checkpt;
+	int checkpt_cur_chunk;
+	int checkpt_cur_block;
+	int checkpt_next_block;
+	int *checkpt_block_list;
+	int checkpt_max_blocks;
+	u32 checkpt_sum;
+	u32 checkpt_xor;
+
+	int checkpoint_blocks_required;	/* Number of blocks needed to store
+					 * current checkpoint set */
+
+	/* Block Info */
+	struct yaffs_block_info *block_info;
+	u8 *chunk_bits;		/* bitmap of chunks in use */
+	unsigned block_info_alt:1;	/* allocated using alternative alloc */
+	unsigned chunk_bits_alt:1;	/* allocated using alternative alloc */
+	int chunk_bit_stride;	/* Number of bytes of chunk_bits per block.
+				 * Must be consistent with chunks_per_block.
+				 */
+
+	int n_erased_blocks;
+	int alloc_block;	/* Current block being allocated off */
+	u32 alloc_page;
+	int alloc_block_finder;	/* Used to search for next allocation block */
+
+	/* Object and Tnode memory management */
+	void *allocator;
+	int n_obj;
+	int n_tnodes;
+
+	int n_hardlinks;
+
+	struct yaffs_obj_bucket obj_bucket[YAFFS_NOBJECT_BUCKETS];
+	u32 bucket_finder;
+
+	int n_free_chunks;
+
+	/* Garbage collection control */
+	u32 *gc_cleanup_list;	/* objects to delete at the end of a GC. */
+	u32 n_clean_ups;
+
+	unsigned has_pending_prioritised_gc;	/* We think this device might
+						have pending prioritised gcs */
+	unsigned gc_disable;
+	unsigned gc_block_finder;
+	unsigned gc_dirtiest;
+	unsigned gc_pages_in_use;
+	unsigned gc_not_done;
+	unsigned gc_block;
+	unsigned gc_chunk;
+	unsigned gc_skip;
+	struct yaffs_summary_tags *gc_sum_tags;
+
+	/* Special directories */
+	struct yaffs_obj *root_dir;
+	struct yaffs_obj *lost_n_found;
+
+	int buffered_block;	/* Which block is buffered here? */
+	int doing_buffered_block_rewrite;
+
+	struct yaffs_cache *cache;
+	int cache_last_use;
+
+	/* Stuff for background deletion and unlinked files. */
+	struct yaffs_obj *unlinked_dir;	/* Directory where unlinked and deleted
+					 files live. */
+	struct yaffs_obj *del_dir;	/* Directory where deleted objects are
+					sent to disappear. */
+	struct yaffs_obj *unlinked_deletion;	/* Current file being
+							background deleted. */
+	int n_deleted_files;	/* Count of files awaiting deletion; */
+	int n_unlinked_files;	/* Count of unlinked files. */
+	int n_bg_deletions;	/* Count of background deletions. */
+
+	/* Temporary buffer management */
+	struct yaffs_buffer temp_buffer[YAFFS_N_TEMP_BUFFERS];
+	int max_temp;
+	int temp_in_use;
+	int unmanaged_buffer_allocs;
+	int unmanaged_buffer_deallocs;
+
+	/* yaffs2 runtime stuff */
+	unsigned seq_number;	/* Sequence number of currently
+					allocating block */
+	unsigned oldest_dirty_seq;
+	unsigned oldest_dirty_block;
+
+	/* Block refreshing */
+	int refresh_skip;	/* A skip down counter.
+				 * Refresh happens when this gets to zero. */
+
+	/* Dirty directory handling */
+	struct list_head dirty_dirs;	/* List of dirty directories */
+
+	/* Summary */
+	int chunks_per_summary;
+	struct yaffs_summary_tags *sum_tags;
+
+	/* Statistics */
+	u32 n_page_writes;
+	u32 n_page_reads;
+	u32 n_erasures;
+	u32 n_erase_failures;
+	u32 n_gc_copies;
+	u32 all_gcs;
+	u32 passive_gc_count;
+	u32 oldest_dirty_gc_count;
+	u32 n_gc_blocks;
+	u32 bg_gcs;
+	u32 n_retried_writes;
+	u32 n_retired_blocks;
+	u32 n_ecc_fixed;
+	u32 n_ecc_unfixed;
+	u32 n_tags_ecc_fixed;
+	u32 n_tags_ecc_unfixed;
+	u32 n_deletions;
+	u32 n_unmarked_deletions;
+	u32 refresh_count;
+	u32 cache_hits;
+	u32 tags_used;
+	u32 summary_used;
+
+};
+
+/* The CheckpointDevice structure holds the device information that changes
+ *at runtime and must be preserved over unmount/mount cycles.
+ */
+struct yaffs_checkpt_dev {
+	int struct_type;
+	int n_erased_blocks;
+	int alloc_block;	/* Current block being allocated off */
+	u32 alloc_page;
+	int n_free_chunks;
+
+	int n_deleted_files;	/* Count of files awaiting deletion; */
+	int n_unlinked_files;	/* Count of unlinked files. */
+	int n_bg_deletions;	/* Count of background deletions. */
+
+	/* yaffs2 runtime stuff */
+	unsigned seq_number;	/* Sequence number of currently
+				 * allocating block */
+
+};
+
+struct yaffs_checkpt_validity {
+	int struct_type;
+	u32 magic;
+	u32 version;
+	u32 head;
+};
+
+struct yaffs_shadow_fixer {
+	int obj_id;
+	int shadowed_id;
+	struct yaffs_shadow_fixer *next;
+};
+
+/* Structure for doing xattr modifications */
+struct yaffs_xattr_mod {
+	int set;		/* If 0 then this is a deletion */
+	const YCHAR *name;
+	const void *data;
+	int size;
+	int flags;
+	int result;
+};
+
+/*----------------------- YAFFS Functions -----------------------*/
+
+int yaffs_guts_initialise(struct yaffs_dev *dev);
+void yaffs_deinitialise(struct yaffs_dev *dev);
+
+int yaffs_get_n_free_chunks(struct yaffs_dev *dev);
+
+int yaffs_rename_obj(struct yaffs_obj *old_dir, const YCHAR * old_name,
+		     struct yaffs_obj *new_dir, const YCHAR * new_name);
+
+int yaffs_unlinker(struct yaffs_obj *dir, const YCHAR * name);
+int yaffs_del_obj(struct yaffs_obj *obj);
+
+int yaffs_get_obj_name(struct yaffs_obj *obj, YCHAR * name, int buffer_size);
+loff_t yaffs_get_obj_length(struct yaffs_obj *obj);
+int yaffs_get_obj_inode(struct yaffs_obj *obj);
+unsigned yaffs_get_obj_type(struct yaffs_obj *obj);
+int yaffs_get_obj_link_count(struct yaffs_obj *obj);
+
+/* File operations */
+int yaffs_file_rd(struct yaffs_obj *obj, u8 * buffer, loff_t offset,
+		  int n_bytes);
+int yaffs_wr_file(struct yaffs_obj *obj, const u8 * buffer, loff_t offset,
+		  int n_bytes, int write_trhrough);
+int yaffs_resize_file(struct yaffs_obj *obj, loff_t new_size);
+
+struct yaffs_obj *yaffs_create_file(struct yaffs_obj *parent,
+				    const YCHAR *name, u32 mode, u32 uid,
+				    u32 gid);
+
+int yaffs_flush_file(struct yaffs_obj *obj, int update_time, int data_sync);
+
+/* Flushing and checkpointing */
+void yaffs_flush_whole_cache(struct yaffs_dev *dev);
+
+int yaffs_checkpoint_save(struct yaffs_dev *dev);
+int yaffs_checkpoint_restore(struct yaffs_dev *dev);
+
+/* Directory operations */
+struct yaffs_obj *yaffs_create_dir(struct yaffs_obj *parent, const YCHAR *name,
+				   u32 mode, u32 uid, u32 gid);
+struct yaffs_obj *yaffs_find_by_name(struct yaffs_obj *the_dir,
+				     const YCHAR *name);
+struct yaffs_obj *yaffs_find_by_number(struct yaffs_dev *dev, u32 number);
+
+/* Link operations */
+struct yaffs_obj *yaffs_link_obj(struct yaffs_obj *parent, const YCHAR *name,
+				 struct yaffs_obj *equiv_obj);
+
+struct yaffs_obj *yaffs_get_equivalent_obj(struct yaffs_obj *obj);
+
+/* Symlink operations */
+struct yaffs_obj *yaffs_create_symlink(struct yaffs_obj *parent,
+				       const YCHAR *name, u32 mode, u32 uid,
+				       u32 gid, const YCHAR *alias);
+YCHAR *yaffs_get_symlink_alias(struct yaffs_obj *obj);
+
+/* Special inodes (fifos, sockets and devices) */
+struct yaffs_obj *yaffs_create_special(struct yaffs_obj *parent,
+				       const YCHAR *name, u32 mode, u32 uid,
+				       u32 gid, u32 rdev);
+
+int yaffs_set_xattrib(struct yaffs_obj *obj, const YCHAR *name,
+		      const void *value, int size, int flags);
+int yaffs_get_xattrib(struct yaffs_obj *obj, const YCHAR *name, void *value,
+		      int size);
+int yaffs_list_xattrib(struct yaffs_obj *obj, char *buffer, int size);
+int yaffs_remove_xattrib(struct yaffs_obj *obj, const YCHAR *name);
+
+/* Special directories */
+struct yaffs_obj *yaffs_root(struct yaffs_dev *dev);
+struct yaffs_obj *yaffs_lost_n_found(struct yaffs_dev *dev);
+
+void yaffs_handle_defered_free(struct yaffs_obj *obj);
+
+void yaffs_update_dirty_dirs(struct yaffs_dev *dev);
+
+int yaffs_bg_gc(struct yaffs_dev *dev, unsigned urgency);
+
+/* Debug dump  */
+int yaffs_dump_obj(struct yaffs_obj *obj);
+
+void yaffs_guts_test(struct yaffs_dev *dev);
+
+/* A few useful functions to be used within the core files*/
+void yaffs_chunk_del(struct yaffs_dev *dev, int chunk_id, int mark_flash,
+		     int lyn);
+int yaffs_check_ff(u8 *buffer, int n_bytes);
+void yaffs_handle_chunk_error(struct yaffs_dev *dev,
+			      struct yaffs_block_info *bi);
+
+u8 *yaffs_get_temp_buffer(struct yaffs_dev *dev);
+void yaffs_release_temp_buffer(struct yaffs_dev *dev, u8 *buffer);
+
+struct yaffs_obj *yaffs_find_or_create_by_number(struct yaffs_dev *dev,
+						 int number,
+						 enum yaffs_obj_type type);
+int yaffs_put_chunk_in_file(struct yaffs_obj *in, int inode_chunk,
+			    int nand_chunk, int in_scan);
+void yaffs_set_obj_name(struct yaffs_obj *obj, const YCHAR *name);
+void yaffs_set_obj_name_from_oh(struct yaffs_obj *obj,
+				const struct yaffs_obj_hdr *oh);
+void yaffs_add_obj_to_dir(struct yaffs_obj *directory, struct yaffs_obj *obj);
+YCHAR *yaffs_clone_str(const YCHAR *str);
+void yaffs_link_fixup(struct yaffs_dev *dev, struct list_head *hard_list);
+void yaffs_block_became_dirty(struct yaffs_dev *dev, int block_no);
+int yaffs_update_oh(struct yaffs_obj *in, const YCHAR *name,
+		    int force, int is_shrink, int shadows,
+		    struct yaffs_xattr_mod *xop);
+void yaffs_handle_shadowed_obj(struct yaffs_dev *dev, int obj_id,
+			       int backward_scanning);
+int yaffs_check_alloc_available(struct yaffs_dev *dev, int n_chunks);
+struct yaffs_tnode *yaffs_get_tnode(struct yaffs_dev *dev);
+struct yaffs_tnode *yaffs_add_find_tnode_0(struct yaffs_dev *dev,
+					   struct yaffs_file_var *file_struct,
+					   u32 chunk_id,
+					   struct yaffs_tnode *passed_tn);
+
+int yaffs_do_file_wr(struct yaffs_obj *in, const u8 *buffer, loff_t offset,
+		     int n_bytes, int write_trhrough);
+void yaffs_resize_file_down(struct yaffs_obj *obj, loff_t new_size);
+void yaffs_skip_rest_of_block(struct yaffs_dev *dev);
+
+int yaffs_count_free_chunks(struct yaffs_dev *dev);
+
+struct yaffs_tnode *yaffs_find_tnode_0(struct yaffs_dev *dev,
+				       struct yaffs_file_var *file_struct,
+				       u32 chunk_id);
+
+u32 yaffs_get_group_base(struct yaffs_dev *dev, struct yaffs_tnode *tn,
+			 unsigned pos);
+
+int yaffs_is_non_empty_dir(struct yaffs_obj *obj);
+
+int yaffs_format_dev(struct yaffs_dev *dev);
+
+void yaffs_addr_to_chunk(struct yaffs_dev *dev, loff_t addr,
+				int *chunk_out, u32 *offset_out);
+/*
+ * Marshalling functions to get loff_t file sizes into aand out of
+ * object headers.
+ */
+void yaffs_oh_size_load(struct yaffs_obj_hdr *oh, loff_t fsize);
+loff_t yaffs_oh_to_size(struct yaffs_obj_hdr *oh);
+loff_t yaffs_max_file_size(struct yaffs_dev *dev);
+
+
+#endif
diff --git a/linux-bsp/asm-study/yaffs2/yaffs2/yaffs_hweight.c b/linux-bsp/asm-study/yaffs2/yaffs2/yaffs_hweight.c
new file mode 100644
index 0000000..7e2c250
--- /dev/null
+++ b/linux-bsp/asm-study/yaffs2/yaffs2/yaffs_hweight.c
@@ -0,0 +1,53 @@
+/*
+ * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
+ *
+ * Copyright (C) 2002-2011 Aleph One Ltd.
+ *   for Toby Churchill Ltd and Brightstar Engineering
+ *
+ * Created by Charles Manning <charles@aleph1.co.uk>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+/* These functions have been renamed to hweightxx to match the
+ * equivaqlent functions in the Linux kernel.
+ */
+
+#include "yaffs_hweight.h"
+
+static const char yaffs_count_bits_table[256] = {
+	0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4,
+	1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5,
+	1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5,
+	2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
+	1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5,
+	2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
+	2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
+	3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7,
+	1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5,
+	2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
+	2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
+	3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7,
+	2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
+	3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7,
+	3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7,
+	4, 5, 5, 6, 5, 6, 6, 7, 5, 6, 6, 7, 6, 7, 7, 8
+};
+
+int yaffs_hweight8(u8 x)
+{
+	int ret_val;
+	ret_val = yaffs_count_bits_table[x];
+	return ret_val;
+}
+
+int yaffs_hweight32(u32 x)
+{
+	return yaffs_hweight8(x & 0xff) +
+		yaffs_hweight8((x >> 8) & 0xff) +
+		yaffs_hweight8((x >> 16) & 0xff) +
+		yaffs_hweight8((x >> 24) & 0xff);
+}
+
diff --git a/linux-bsp/asm-study/yaffs2/yaffs2/yaffs_hweight.h b/linux-bsp/asm-study/yaffs2/yaffs2/yaffs_hweight.h
new file mode 100644
index 0000000..3f7c6c3
--- /dev/null
+++ b/linux-bsp/asm-study/yaffs2/yaffs2/yaffs_hweight.h
@@ -0,0 +1,24 @@
+/*
+ * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
+ *
+ * Copyright (C) 2002-2011 Aleph One Ltd.
+ *   for Toby Churchill Ltd and Brightstar Engineering
+ *
+ * Created by Charles Manning <charles@aleph1.co.uk>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 2.1 as
+ * published by the Free Software Foundation.
+ *
+ * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
+ */
+
+#ifndef __YAFFS_HWEIGHT_H__
+#define __YAFFS_HWEIGHT_H__
+
+#include "yportenv.h"
+
+int yaffs_hweight8(u8 x);
+int yaffs_hweight32(u32 x);
+
+#endif
diff --git a/linux-bsp/asm-study/yaffs2/yaffs2/yaffs_k9f2g08.c b/linux-bsp/asm-study/yaffs2/yaffs2/yaffs_k9f2g08.c
new file mode 100644
index 0000000..421a2a5
--- /dev/null
+++ b/linux-bsp/asm-study/yaffs2/yaffs2/yaffs_k9f2g08.c
@@ -0,0 +1,144 @@
+
+#include "yaffs_k9f2g08.h"
+#include "k9f2g08_api.h"
+#include "yaffs_packedtags2.h"
+#include "yaffs_trace.h"
+
+int ynf_init(struct yaffs_dev *dev)
+{
+	yaffs_trace(YAFFS_TRACE_MTD, "ynf_init on %s", dev->param.name);
+	return YAFFS_OK;
+}
+
+int ynf_write_chunk_tags(struct yaffs_dev *dev, int nand_chunk, const u8 *data, const struct yaffs_ext_tags *tags)
+{
+	struct yaffs_packed_tags2 pt;
+	void *spare;
+	unsigned spareSize = 0;
+
+	yaffs_trace(YAFFS_TRACE_MTD, "ynf_write_chunk_tags chunk %d data %p tags %p", nand_chunk, data, tags);
+
+	/* For yaffs2 writing there must be both data and tags.
+	 * If we're using inband tags, then the tags are stuffed into
+	 * the end of the data buffer.
+	 */
+	if(dev->param.inband_tags){
+		struct yaffs_packed_tags2_tags_only *pt2tp;
+		pt2tp = (struct yaffs_packed_tags2_tags_only *)
+			(data + dev->data_bytes_per_chunk);
+		yaffs_pack_tags2_tags_only(pt2tp,tags);
+		spare = NULL;
+		spareSize = 0;
+	}
+	else{
+		yaffs_pack_tags2(&pt, tags,!dev->param.no_tags_ecc);
+		spare = &pt;
+		spareSize = sizeof(struct yaffs_packed_tags2);
+	}
+
+	return k9f2g08_write(nand_chunk, data, spare, spareSize);
+}
+
+int ynf_read_chunk_tags(struct yaffs_dev *dev, int nand_chunk, u8 *data, struct yaffs_ext_tags *tags)
+{
+	struct yaffs_packed_tags2 pt;
+	int localData = 0;
+	void *spare = NULL;
+	unsigned spareSize;
+	int retval = 0;
+	int eccStatus; //0 = ok, 1 = fixed, -1 = unfixed
+
+	yaffs_trace(YAFFS_TRACE_MTD, "ynf_read_chunk_tags chunk %d data %p tags %p", nand_chunk, data, tags);
+
+	if(!tags){
+		spare = NULL;
+		spareSize = 0;
+	}else if(dev->param.inband_tags){
+
+		if(!data) {
+			localData = 1;
+			data = yaffs_get_temp_buffer(dev);
+		}
+		spare = NULL;
+		spareSize = 0;
+	}
+	else {
+		spare = &pt;
+		spareSize = sizeof(struct yaffs_packed_tags2);
+	}
+
+	retval = k9f2g08_read(nand_chunk, data, spare, spareSize, &eccStatus);
+
+	if(dev->param.inband_tags){
+		if(tags){
+			struct yaffs_packed_tags2_tags_only * pt2tp;
+			pt2tp = (struct yaffs_packed_tags2_tags_only *)&data[dev->data_bytes_per_chunk];
+			yaffs_unpack_tags2_tags_only(tags,pt2tp);
+		}
+	}
+	else {
+		if (tags){
+			yaffs_unpack_tags2(tags, &pt,!dev->param.no_tags_ecc);
+		}
+	}
+
+
+	if(tags && tags->chunk_used){
+		if(eccStatus < 0 ||
+		   tags->ecc_result == YAFFS_ECC_RESULT_UNFIXED)
+			tags->ecc_result = YAFFS_ECC_RESULT_UNFIXED;
+		else if(eccStatus > 0 ||
+			     tags->ecc_result == YAFFS_ECC_RESULT_FIXED)
+			tags->ecc_result = YAFFS_ECC_RESULT_FIXED;
+		else
+			tags->ecc_result = YAFFS_ECC_RESULT_NO_ERROR;
+	}
+
+	if(localData)
+		yaffs_release_temp_buffer(dev, data);
+
+	return retval;
+}
+
+int ynf_mark_block_bad(struct yaffs_dev *dev, int blockId)
+{
+	yaffs_trace(YAFFS_TRACE_MTD, "ynf_mark_block_bad block@%d ", blockId);
+	return k9f2g08_mark_block_bad(blockId);
+}
+
+int ynf_erase_block(struct yaffs_dev *dev, int blockId)
+{
+	yaffs_trace(YAFFS_TRACE_MTD, "ynf_erase_block   block@%d ", blockId);
+	return k9f2g08_erase_block(blockId);
+}
+
+
+int ynf_query_block(struct yaffs_dev *dev, int blockId, enum yaffs_block_state *state, u32 *seq_number)
+{
+	unsigned chunkNo;
+	struct yaffs_ext_tags tags;
+
+	yaffs_trace(YAFFS_TRACE_MTD, "ynf_query_block   block@%d ", blockId);
+	*seq_number = 0;
+
+	chunkNo = blockId * dev->param.chunks_per_block;
+
+	if (!k9f2g08_is_block_ok(blockId)) {
+		*state = YAFFS_BLOCK_STATE_DEAD;
+		return YAFFS_OK;
+	}
+
+	ynf_read_chunk_tags(dev, chunkNo, NULL, &tags);
+	if(!tags.chunk_used)
+	{
+		*state = YAFFS_BLOCK_STATE_EMPTY;
+	}
+	else
+	{
+		*state = YAFFS_BLOCK_STATE_NEEDS_SCAN;
+		*seq_number = tags.seq_number;
+	}
+	return YAFFS_OK;
+}
+
+
diff --git a/linux-bsp/asm-study/yaffs2/yaffs2/yaffs_k9f2g08.h b/linux-bsp/asm-study/yaffs2/yaffs2/yaffs_k9f2g08.h
new file mode 100644
index 0000000..54252df
--- /dev/null
+++ b/linux-bsp/asm-study/yaffs2/yaffs2/yaffs_k9f2g08.h
@@ -0,0 +1,13 @@
+#ifndef __YAFFS_K9F2G08_H__
+#define __YAFFS_K9F2G08_H__
+
+#include "yaffs_guts.h"
+
+int ynf_init(struct yaffs_dev *dev);
+int ynf_mark_block_bad(struct yaffs_dev *dev,int blockNumber);
+int ynf_query_block(struct yaffs_dev *dev, int block_no, enum yaffs_block_state *state, u32 *seq_number);
+int ynf_write_chunk_tags(struct yaffs_dev *dev,int nand_chunk,const u8 *data, const struct yaffs_ext_tags *tags);
+int ynf_read_chunk_tags(struct yaffs_dev *dev,int nand_chunk, u8 *data, struct yaffs_ext_tags *tags);
+int ynf_erase_block(struct yaffs_dev *dev, int block_num);
+
+#endif /* __YAFFS_K9F2G08_H__  */
diff --git a/linux-bsp/asm-study/yaffs2/yaffs2/yaffs_list.h b/linux-bsp/asm-study/yaffs2/yaffs2/yaffs_list.h
new file mode 100644
index 0000000..a7afaea
--- /dev/null
+++ b/linux-bsp/asm-study/yaffs2/yaffs2/yaffs_list.h
@@ -0,0 +1,126 @@
+/*
+ * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
+ *
+ * Copyright (C) 2002-2011 Aleph One Ltd.
+ *   for Toby Churchill Ltd and Brightstar Engineering
+ *
+ * Created by Charles Manning <charles@aleph1.co.uk>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 2.1 as
+ * published by the Free Software Foundation.
+ *
+ * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
+ */
+
+/*
+ * This file is just holds extra declarations of macros that would normally
+ * be providesd in the Linux kernel. These macros have been written from
+ * scratch but are functionally equivalent to the Linux ones.
+ *
+ */
+
+#ifndef __YAFFS_LIST_H__
+#define __YAFFS_LIST_H__
+
+
+/*
+ * This is a simple doubly linked list implementation that matches the
+ * way the Linux kernel doubly linked list implementation works.
+ */
+
+struct list_head {
+	struct list_head *next; /* next in chain */
+	struct list_head *prev; /* previous in chain */
+};
+
+
+/* Initialise a static list */
+#define LIST_HEAD(name) \
+struct list_head name = { &(name), &(name)}
+
+
+
+/* Initialise a list head to an empty list */
+#define INIT_LIST_HEAD(p) \
+do { \
+	(p)->next = (p);\
+	(p)->prev = (p); \
+} while (0)
+
+
+/* Add an element to a list */
+static inline void list_add(struct list_head *new_entry,
+				struct list_head *list)
+{
+	struct list_head *list_next = list->next;
+
+	list->next = new_entry;
+	new_entry->prev = list;
+	new_entry->next = list_next;
+	list_next->prev = new_entry;
+
+}
+
+static inline void list_add_tail(struct list_head *new_entry,
+				 struct list_head *list)
+{
+	struct list_head *list_prev = list->prev;
+
+	list->prev = new_entry;
+	new_entry->next = list;
+	new_entry->prev = list_prev;
+	list_prev->next = new_entry;
+
+}
+
+
+/* Take an element out of its current list, with or without
+ * reinitialising the links.of the entry*/
+static inline void list_del(struct list_head *entry)
+{
+	struct list_head *list_next = entry->next;
+	struct list_head *list_prev = entry->prev;
+
+	list_next->prev = list_prev;
+	list_prev->next = list_next;
+
+}
+
+static inline void list_del_init(struct list_head *entry)
+{
+	list_del(entry);
+	entry->next = entry->prev = entry;
+}
+
+
+/* Test if the list is empty */
+static inline int list_empty(struct list_head *entry)
+{
+	return (entry->next == entry);
+}
+
+
+/* list_entry takes a pointer to a list entry and offsets it to that
+ * we can find a pointer to the object it is embedded in.
+ */
+
+
+#define list_entry(entry, type, member) \
+	((type *)((char *)(entry)-(unsigned long)(&((type *)NULL)->member)))
+
+
+/* list_for_each and list_for_each_safe  iterate over lists.
+ * list_for_each_safe uses temporary storage to make the list delete safe
+ */
+
+#define list_for_each(itervar, list) \
+	for (itervar = (list)->next; itervar != (list); itervar = itervar->next)
+
+#define list_for_each_safe(itervar, save_var, list) \
+	for (itervar = (list)->next, save_var = (list)->next->next; \
+		itervar != (list); \
+		itervar = save_var, save_var = save_var->next)
+
+
+#endif
diff --git a/linux-bsp/asm-study/yaffs2/yaffs2/yaffs_nameval.c b/linux-bsp/asm-study/yaffs2/yaffs2/yaffs_nameval.c
new file mode 100644
index 0000000..4bdf4ed
--- /dev/null
+++ b/linux-bsp/asm-study/yaffs2/yaffs2/yaffs_nameval.c
@@ -0,0 +1,208 @@
+/*
+ * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
+ *
+ * Copyright (C) 2002-2011 Aleph One Ltd.
+ *   for Toby Churchill Ltd and Brightstar Engineering
+ *
+ * Created by Charles Manning <charles@aleph1.co.uk>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+/*
+ * This simple implementation of a name-value store assumes a small number of
+* values and fits into a small finite buffer.
+ *
+ * Each attribute is stored as a record:
+ *  sizeof(int) bytes   record size.
+ *  strnlen+1 bytes name null terminated.
+ *  nbytes    value.
+ *  ----------
+ *  total size  stored in record size
+ *
+ * This code has not been tested with unicode yet.
+ */
+
+#include "yaffs_nameval.h"
+
+#include "yportenv.h"
+
+static int nval_find(const char *xb, int xb_size, const YCHAR *name,
+		     int *exist_size)
+{
+	int pos = 0;
+	int size;
+
+	memcpy(&size, xb, sizeof(int));
+	while (size > 0 && (size < xb_size) && (pos + size < xb_size)) {
+		if (!strncmp((YCHAR *) (xb + pos + sizeof(int)),
+				name, size)) {
+			if (exist_size)
+				*exist_size = size;
+			return pos;
+		}
+		pos += size;
+		if (pos < xb_size - sizeof(int))
+			memcpy(&size, xb + pos, sizeof(int));
+		else
+			size = 0;
+	}
+	if (exist_size)
+		*exist_size = 0;
+	return -ENODATA;
+}
+
+static int nval_used(const char *xb, int xb_size)
+{
+	int pos = 0;
+	int size;
+
+	memcpy(&size, xb + pos, sizeof(int));
+	while (size > 0 && (size < xb_size) && (pos + size < xb_size)) {
+		pos += size;
+		if (pos < xb_size - sizeof(int))
+			memcpy(&size, xb + pos, sizeof(int));
+		else
+			size = 0;
+	}
+	return pos;
+}
+
+int nval_del(char *xb, int xb_size, const YCHAR *name)
+{
+	int pos = nval_find(xb, xb_size, name, NULL);
+	int size;
+
+	if (pos < 0 || pos >= xb_size)
+		return -ENODATA;
+
+	/* Find size, shift rest over this record,
+	 * then zero out the rest of buffer */
+	memcpy(&size, xb + pos, sizeof(int));
+	memcpy(xb + pos, xb + pos + size, xb_size - (pos + size));
+	memset(xb + (xb_size - size), 0, size);
+	return 0;
+}
+
+int nval_set(char *xb, int xb_size, const YCHAR *name, const char *buf,
+		int bsize, int flags)
+{
+	int pos;
+	int namelen = strnlen(name, xb_size);
+	int reclen;
+	int size_exist = 0;
+	int space;
+	int start;
+
+	pos = nval_find(xb, xb_size, name, &size_exist);
+
+	if (flags & XATTR_CREATE && pos >= 0)
+		return -EEXIST;
+	if (flags & XATTR_REPLACE && pos < 0)
+		return -ENODATA;
+
+	start = nval_used(xb, xb_size);
+	space = xb_size - start + size_exist;
+
+	reclen = (sizeof(int) + namelen + 1 + bsize);
+
+	if (reclen > space)
+		return -ENOSPC;
+
+	if (pos >= 0) {
+		nval_del(xb, xb_size, name);
+		start = nval_used(xb, xb_size);
+	}
+
+	pos = start;
+
+	memcpy(xb + pos, &reclen, sizeof(int));
+	pos += sizeof(int);
+	strncpy((YCHAR *) (xb + pos), name, reclen);
+	pos += (namelen + 1);
+	memcpy(xb + pos, buf, bsize);
+	return 0;
+}
+
+int nval_get(const char *xb, int xb_size, const YCHAR * name, char *buf,
+	     int bsize)
+{
+	int pos = nval_find(xb, xb_size, name, NULL);
+	int size;
+
+	if (pos >= 0 && pos < xb_size) {
+
+		memcpy(&size, xb + pos, sizeof(int));
+		pos += sizeof(int);	/* advance past record length */
+		size -= sizeof(int);
+
+		/* Advance over name string */
+		while (xb[pos] && size > 0 && pos < xb_size) {
+			pos++;
+			size--;
+		}
+		/*Advance over NUL */
+		pos++;
+		size--;
+
+		/* If bsize is zero then this is a size query.
+		 * Return the size, but don't copy.
+		 */
+		if (!bsize)
+			return size;
+
+		if (size <= bsize) {
+			memcpy(buf, xb + pos, size);
+			return size;
+		}
+	}
+	if (pos >= 0)
+		return -ERANGE;
+
+	return -ENODATA;
+}
+
+int nval_list(const char *xb, int xb_size, char *buf, int bsize)
+{
+	int pos = 0;
+	int size;
+	int name_len;
+	int ncopied = 0;
+	int filled = 0;
+
+	memcpy(&size, xb + pos, sizeof(int));
+	while (size > sizeof(int) &&
+		size <= xb_size &&
+		(pos + size) < xb_size &&
+		!filled) {
+		pos += sizeof(int);
+		size -= sizeof(int);
+		name_len = strnlen((YCHAR *) (xb + pos), size);
+		if (ncopied + name_len + 1 < bsize) {
+			memcpy(buf, xb + pos, name_len * sizeof(YCHAR));
+			buf += name_len;
+			*buf = '\0';
+			buf++;
+			if (sizeof(YCHAR) > 1) {
+				*buf = '\0';
+				buf++;
+			}
+			ncopied += (name_len + 1);
+		} else {
+			filled = 1;
+		}
+		pos += size;
+		if (pos < xb_size - sizeof(int))
+			memcpy(&size, xb + pos, sizeof(int));
+		else
+			size = 0;
+	}
+	return ncopied;
+}
+
+int nval_hasvalues(const char *xb, int xb_size)
+{
+	return nval_used(xb, xb_size) > 0;
+}
diff --git a/linux-bsp/asm-study/yaffs2/yaffs2/yaffs_nameval.h b/linux-bsp/asm-study/yaffs2/yaffs2/yaffs_nameval.h
new file mode 100644
index 0000000..951e64f
--- /dev/null
+++ b/linux-bsp/asm-study/yaffs2/yaffs2/yaffs_nameval.h
@@ -0,0 +1,28 @@
+/*
+ * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
+ *
+ * Copyright (C) 2002-2011 Aleph One Ltd.
+ *   for Toby Churchill Ltd and Brightstar Engineering
+ *
+ * Created by Charles Manning <charles@aleph1.co.uk>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 2.1 as
+ * published by the Free Software Foundation.
+ *
+ * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
+ */
+
+#ifndef __NAMEVAL_H__
+#define __NAMEVAL_H__
+
+#include "yportenv.h"
+
+int nval_del(char *xb, int xb_size, const YCHAR * name);
+int nval_set(char *xb, int xb_size, const YCHAR * name, const char *buf,
+	     int bsize, int flags);
+int nval_get(const char *xb, int xb_size, const YCHAR * name, char *buf,
+	     int bsize);
+int nval_list(const char *xb, int xb_size, char *buf, int bsize);
+int nval_hasvalues(const char *xb, int xb_size);
+#endif
diff --git a/linux-bsp/asm-study/yaffs2/yaffs2/yaffs_nand.c b/linux-bsp/asm-study/yaffs2/yaffs2/yaffs_nand.c
new file mode 100644
index 0000000..165d010
--- /dev/null
+++ b/linux-bsp/asm-study/yaffs2/yaffs2/yaffs_nand.c
@@ -0,0 +1,120 @@
+/*
+ * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
+ *
+ * Copyright (C) 2002-2011 Aleph One Ltd.
+ *   for Toby Churchill Ltd and Brightstar Engineering
+ *
+ * Created by Charles Manning <charles@aleph1.co.uk>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include "yaffs_nand.h"
+#include "yaffs_tagscompat.h"
+
+#include "yaffs_getblockinfo.h"
+#include "yaffs_summary.h"
+
+int yaffs_rd_chunk_tags_nand(struct yaffs_dev *dev, int nand_chunk,
+			     u8 *buffer, struct yaffs_ext_tags *tags)
+{
+	int result;
+	struct yaffs_ext_tags local_tags;
+	int flash_chunk = nand_chunk - dev->chunk_offset;
+
+	dev->n_page_reads++;
+
+	/* If there are no tags provided use local tags. */
+	if (!tags)
+		tags = &local_tags;
+
+	if (dev->param.read_chunk_tags_fn)
+		result =
+		    dev->param.read_chunk_tags_fn(dev, flash_chunk, buffer,
+						  tags);
+	else
+		result = yaffs_tags_compat_rd(dev,
+					      flash_chunk, buffer, tags);
+	if (tags && tags->ecc_result > YAFFS_ECC_RESULT_NO_ERROR) {
+
+		struct yaffs_block_info *bi;
+		bi = yaffs_get_block_info(dev,
+					  nand_chunk /
+					  dev->param.chunks_per_block);
+		yaffs_handle_chunk_error(dev, bi);
+	}
+	return result;
+}
+
+int yaffs_wr_chunk_tags_nand(struct yaffs_dev *dev,
+				int nand_chunk,
+				const u8 *buffer, struct yaffs_ext_tags *tags)
+{
+	int result;
+	int flash_chunk = nand_chunk - dev->chunk_offset;
+
+	dev->n_page_writes++;
+
+	if (tags) {
+		tags->seq_number = dev->seq_number;
+		tags->chunk_used = 1;
+		yaffs_trace(YAFFS_TRACE_WRITE,
+			"Writing chunk %d tags %d %d",
+			nand_chunk, tags->obj_id, tags->chunk_id);
+	} else {
+		yaffs_trace(YAFFS_TRACE_ERROR, "Writing with no tags");
+		BUG();
+		return YAFFS_FAIL;
+	}
+
+	if (dev->param.write_chunk_tags_fn)
+		result = dev->param.write_chunk_tags_fn(dev, flash_chunk,
+							buffer, tags);
+	else
+		result = yaffs_tags_compat_wr(dev, flash_chunk, buffer, tags);
+
+	yaffs_summary_add(dev, tags, nand_chunk);
+
+	return result;
+}
+
+int yaffs_mark_bad(struct yaffs_dev *dev, int block_no)
+{
+	block_no -= dev->block_offset;
+	if (dev->param.bad_block_fn)
+		return dev->param.bad_block_fn(dev, block_no);
+
+	return yaffs_tags_compat_mark_bad(dev, block_no);
+}
+
+int yaffs_query_init_block_state(struct yaffs_dev *dev,
+				 int block_no,
+				 enum yaffs_block_state *state,
+				 u32 *seq_number)
+{
+	block_no -= dev->block_offset;
+	if (dev->param.query_block_fn)
+		return dev->param.query_block_fn(dev, block_no, state,
+						 seq_number);
+
+	return yaffs_tags_compat_query_block(dev, block_no, state, seq_number);
+}
+
+int yaffs_erase_block(struct yaffs_dev *dev, int flash_block)
+{
+	int result;
+
+	flash_block -= dev->block_offset;
+	dev->n_erasures++;
+	result = dev->param.erase_fn(dev, flash_block);
+	return result;
+}
+
+int yaffs_init_nand(struct yaffs_dev *dev)
+{
+	if (dev->param.initialise_flash_fn)
+		return dev->param.initialise_flash_fn(dev);
+	return YAFFS_OK;
+}
diff --git a/linux-bsp/asm-study/yaffs2/yaffs2/yaffs_nand.h b/linux-bsp/asm-study/yaffs2/yaffs2/yaffs_nand.h
new file mode 100644
index 0000000..7134662
--- /dev/null
+++ b/linux-bsp/asm-study/yaffs2/yaffs2/yaffs_nand.h
@@ -0,0 +1,38 @@
+/*
+ * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
+ *
+ * Copyright (C) 2002-2011 Aleph One Ltd.
+ *   for Toby Churchill Ltd and Brightstar Engineering
+ *
+ * Created by Charles Manning <charles@aleph1.co.uk>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 2.1 as
+ * published by the Free Software Foundation.
+ *
+ * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
+ */
+
+#ifndef __YAFFS_NAND_H__
+#define __YAFFS_NAND_H__
+#include "yaffs_guts.h"
+
+int yaffs_rd_chunk_tags_nand(struct yaffs_dev *dev, int nand_chunk,
+			     u8 *buffer, struct yaffs_ext_tags *tags);
+
+int yaffs_wr_chunk_tags_nand(struct yaffs_dev *dev,
+			     int nand_chunk,
+			     const u8 *buffer, struct yaffs_ext_tags *tags);
+
+int yaffs_mark_bad(struct yaffs_dev *dev, int block_no);
+
+int yaffs_query_init_block_state(struct yaffs_dev *dev,
+				 int block_no,
+				 enum yaffs_block_state *state,
+				 unsigned *seq_number);
+
+int yaffs_erase_block(struct yaffs_dev *dev, int flash_block);
+
+int yaffs_init_nand(struct yaffs_dev *dev);
+
+#endif
diff --git a/linux-bsp/asm-study/yaffs2/yaffs2/yaffs_osglue.c b/linux-bsp/asm-study/yaffs2/yaffs2/yaffs_osglue.c
new file mode 100644
index 0000000..d24a7b7
--- /dev/null
+++ b/linux-bsp/asm-study/yaffs2/yaffs2/yaffs_osglue.c
@@ -0,0 +1,170 @@
+/*
+ * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
+ *
+ * Copyright (C) 2002-2011 Aleph One Ltd.
+ *   for Toby Churchill Ltd and Brightstar Engineering
+ *
+ * Created by Charles Manning <charles@aleph1.co.uk>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+/* 
+ * Example OS glue functions for running on a Linux/POSIX system.
+ */
+
+#include "yaffscfg.h"
+#include "yaffs_guts.h"
+#include "yaffsfs.h"
+#include "yaffs_trace.h"
+#include "yportenv.h"
+
+
+/*
+ * yaffsfs_SetError() and yaffsfs_GetError()
+ * Do whatever to set the system error.
+ * yaffsfs_GetError() just fetches the last error.
+ */
+static int errno;
+
+static int yaffsfs_lastError;
+
+void yaffsfs_SetError(int err)
+{
+	//Do whatever to set error
+	yaffsfs_lastError = err;
+	errno = err;
+}
+
+int yaffsfs_GetLastError(void)
+{
+	return yaffsfs_lastError;
+}
+
+/*
+ * yaffsfs_CheckMemRegion()
+ * Check that access to an address is valid.
+ * This can check memory is in bounds and is writable etc.
+ *
+ * Returns 0 if ok, negative if not.
+ */
+int yaffsfs_CheckMemRegion(const void *addr, size_t size, int write_request)
+{
+	if(!addr)
+		return -1;
+	return 0;
+}
+
+/*
+ * yaffsfs_Lock()
+ * yaffsfs_Unlock()
+ * A single mechanism to lock and unlock yaffs. Hook up to a mutex or whatever.
+ * Here are two examples, one using POSIX pthreads, the other doing nothing.
+ */
+
+#ifdef CONFIG_YAFFS_USE_PTHREADS
+#include <pthread.h>
+static pthread_mutex_t mutex1;
+
+
+void yaffsfs_Lock(void)
+{
+	pthread_mutex_lock( &mutex1 );
+}
+
+void yaffsfs_Unlock(void)
+{
+	pthread_mutex_unlock( &mutex1 );
+}
+
+void yaffsfs_LockInit(void)
+{
+	pthread_mutex_init( &mutex1, NULL);
+}
+
+#else
+
+void yaffsfs_Lock(void)
+{
+}
+
+void yaffsfs_Unlock(void)
+{
+}
+
+void yaffsfs_LockInit(void)
+{
+}
+#endif
+
+/*
+ * yaffsfs_CurrentTime() retrns a 32-bit timestamp.
+ * 
+ * Can return 0 if your system does not care about time.
+ */
+ 
+u32 yaffsfs_CurrentTime(void)
+{
+    return 0;
+	//return time(NULL);
+}
+
+
+/*
+ * yaffsfs_malloc()
+ * yaffsfs_free()
+ *
+ * Functions to allocate and free memory.
+ */
+ 
+#ifdef CONFIG_YAFFS_TEST_MALLOC
+
+static int yaffs_kill_alloc = 0;
+static size_t total_malloced = 0;
+static size_t malloc_limit = 0 & 6000000;
+
+void *yaffsfs_malloc(size_t size)
+{
+	void * this;
+	if(yaffs_kill_alloc)
+		return NULL;
+	if(malloc_limit && malloc_limit <(total_malloced + size) )
+		return NULL;
+
+	this = malloc(size);
+	if(this)
+		total_malloced += size;
+	return this;
+}
+
+#else
+
+void *yaffsfs_malloc(size_t size)
+{
+	return malloc(size);
+}
+
+#endif
+
+void yaffsfs_free(void *ptr)
+{
+	free(ptr);
+}
+
+void yaffsfs_OSInitialisation(void)
+{
+	yaffsfs_LockInit();
+}
+
+/*
+ * yaffs_bug_fn()
+ * Function to report a bug.
+ */
+ 
+void yaffs_bug_fn(const char *file_name, int line_no)
+{
+	printf("yaffs bug detected %s:%d\n",
+		file_name, line_no);
+}
diff --git a/linux-bsp/asm-study/yaffs2/yaffs2/yaffs_osglue.h b/linux-bsp/asm-study/yaffs2/yaffs2/yaffs_osglue.h
new file mode 100644
index 0000000..739dddb
--- /dev/null
+++ b/linux-bsp/asm-study/yaffs2/yaffs2/yaffs_osglue.h
@@ -0,0 +1,44 @@
+/*
+ * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
+ *
+ * Copyright (C) 2002-2011 Aleph One Ltd.
+ *   for Toby Churchill Ltd and Brightstar Engineering
+ *
+ * Created by Charles Manning <charles@aleph1.co.uk>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 2.1 as
+ * published by the Free Software Foundation.
+ *
+ * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
+ */
+
+/*
+ * Header file for using yaffs in an application via
+ * a direct interface.
+ */
+
+
+#ifndef __YAFFS_OSGLUE_H__
+#define __YAFFS_OSGLUE_H__
+
+
+#include "yportenv.h"
+
+void yaffsfs_Lock(void);
+void yaffsfs_Unlock(void);
+
+u32 yaffsfs_CurrentTime(void);
+
+void yaffsfs_SetError(int err);
+
+void *yaffsfs_malloc(size_t size);
+void yaffsfs_free(void *ptr);
+
+int yaffsfs_CheckMemRegion(const void *addr, size_t size, int write_request);
+
+void yaffsfs_OSInitialisation(void);
+
+
+#endif
+
diff --git a/linux-bsp/asm-study/yaffs2/yaffs2/yaffs_packedtags2.c b/linux-bsp/asm-study/yaffs2/yaffs2/yaffs_packedtags2.c
new file mode 100644
index 0000000..e1d18cc
--- /dev/null
+++ b/linux-bsp/asm-study/yaffs2/yaffs2/yaffs_packedtags2.c
@@ -0,0 +1,197 @@
+/*
+ * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
+ *
+ * Copyright (C) 2002-2011 Aleph One Ltd.
+ *   for Toby Churchill Ltd and Brightstar Engineering
+ *
+ * Created by Charles Manning <charles@aleph1.co.uk>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include "yaffs_packedtags2.h"
+#include "yportenv.h"
+#include "yaffs_trace.h"
+
+/* This code packs a set of extended tags into a binary structure for
+ * NAND storage
+ */
+
+/* Some of the information is "extra" struff which can be packed in to
+ * speed scanning
+ * This is defined by having the EXTRA_HEADER_INFO_FLAG set.
+ */
+
+/* Extra flags applied to chunk_id */
+
+#define EXTRA_HEADER_INFO_FLAG	0x80000000
+#define EXTRA_SHRINK_FLAG	0x40000000
+#define EXTRA_SHADOWS_FLAG	0x20000000
+#define EXTRA_SPARE_FLAGS	0x10000000
+
+#define ALL_EXTRA_FLAGS		0xf0000000
+
+/* Also, the top 4 bits of the object Id are set to the object type. */
+#define EXTRA_OBJECT_TYPE_SHIFT (28)
+#define EXTRA_OBJECT_TYPE_MASK  ((0x0f) << EXTRA_OBJECT_TYPE_SHIFT)
+
+static void yaffs_dump_packed_tags2_tags_only(
+				const struct yaffs_packed_tags2_tags_only *ptt)
+{
+	yaffs_trace(YAFFS_TRACE_MTD,
+		"packed tags obj %d chunk %d byte %d seq %d",
+		ptt->obj_id, ptt->chunk_id, ptt->n_bytes, ptt->seq_number);
+}
+
+static void yaffs_dump_packed_tags2(const struct yaffs_packed_tags2 *pt)
+{
+	yaffs_dump_packed_tags2_tags_only(&pt->t);
+}
+
+static void yaffs_dump_tags2(const struct yaffs_ext_tags *t)
+{
+	yaffs_trace(YAFFS_TRACE_MTD,
+		"ext.tags eccres %d blkbad %d chused %d obj %d chunk%d byte %d del %d ser %d seq %d",
+		t->ecc_result, t->block_bad, t->chunk_used, t->obj_id,
+		t->chunk_id, t->n_bytes, t->is_deleted, t->serial_number,
+		t->seq_number);
+
+}
+
+static int yaffs_check_tags_extra_packable(const struct yaffs_ext_tags *t)
+{
+	if (t->chunk_id != 0 || !t->extra_available)
+		return 0;
+
+	/* Check if the file size is too long to store */
+	if (t->extra_obj_type == YAFFS_OBJECT_TYPE_FILE &&
+	    (t->extra_file_size >> 31) != 0)
+		return 0;
+	return 1;
+}
+
+void yaffs_pack_tags2_tags_only(struct yaffs_packed_tags2_tags_only *ptt,
+				const struct yaffs_ext_tags *t)
+{
+	ptt->chunk_id = t->chunk_id;
+	ptt->seq_number = t->seq_number;
+	ptt->n_bytes = t->n_bytes;
+	ptt->obj_id = t->obj_id;
+
+	/* Only store extra tags for object headers.
+	 * If it is a file then only store  if the file size is short\
+	 * enough to fit.
+	 */
+	if (yaffs_check_tags_extra_packable(t)) {
+		/* Store the extra header info instead */
+		/* We save the parent object in the chunk_id */
+		ptt->chunk_id = EXTRA_HEADER_INFO_FLAG | t->extra_parent_id;
+		if (t->extra_is_shrink)
+			ptt->chunk_id |= EXTRA_SHRINK_FLAG;
+		if (t->extra_shadows)
+			ptt->chunk_id |= EXTRA_SHADOWS_FLAG;
+
+		ptt->obj_id &= ~EXTRA_OBJECT_TYPE_MASK;
+		ptt->obj_id |= (t->extra_obj_type << EXTRA_OBJECT_TYPE_SHIFT);
+
+		if (t->extra_obj_type == YAFFS_OBJECT_TYPE_HARDLINK)
+			ptt->n_bytes = t->extra_equiv_id;
+		else if (t->extra_obj_type == YAFFS_OBJECT_TYPE_FILE)
+			ptt->n_bytes = (unsigned) t->extra_file_size;
+		else
+			ptt->n_bytes = 0;
+	}
+
+	yaffs_dump_packed_tags2_tags_only(ptt);
+	yaffs_dump_tags2(t);
+}
+
+void yaffs_pack_tags2(struct yaffs_packed_tags2 *pt,
+		      const struct yaffs_ext_tags *t, int tags_ecc)
+{
+	yaffs_pack_tags2_tags_only(&pt->t, t);
+
+	if (tags_ecc)
+		yaffs_ecc_calc_other((unsigned char *)&pt->t,
+				    sizeof(struct yaffs_packed_tags2_tags_only),
+				    &pt->ecc);
+}
+
+void yaffs_unpack_tags2_tags_only(struct yaffs_ext_tags *t,
+				  struct yaffs_packed_tags2_tags_only *ptt)
+{
+	memset(t, 0, sizeof(struct yaffs_ext_tags));
+
+	if (ptt->seq_number == 0xffffffff)
+		return;
+
+	t->block_bad = 0;
+	t->chunk_used = 1;
+	t->obj_id = ptt->obj_id;
+	t->chunk_id = ptt->chunk_id;
+	t->n_bytes = ptt->n_bytes;
+	t->is_deleted = 0;
+	t->serial_number = 0;
+	t->seq_number = ptt->seq_number;
+
+	/* Do extra header info stuff */
+	if (ptt->chunk_id & EXTRA_HEADER_INFO_FLAG) {
+		t->chunk_id = 0;
+		t->n_bytes = 0;
+
+		t->extra_available = 1;
+		t->extra_parent_id = ptt->chunk_id & (~(ALL_EXTRA_FLAGS));
+		t->extra_is_shrink = ptt->chunk_id & EXTRA_SHRINK_FLAG ? 1 : 0;
+		t->extra_shadows = ptt->chunk_id & EXTRA_SHADOWS_FLAG ? 1 : 0;
+		t->extra_obj_type = ptt->obj_id >> EXTRA_OBJECT_TYPE_SHIFT;
+		t->obj_id &= ~EXTRA_OBJECT_TYPE_MASK;
+
+		if (t->extra_obj_type == YAFFS_OBJECT_TYPE_HARDLINK)
+			t->extra_equiv_id = ptt->n_bytes;
+		else
+			t->extra_file_size = ptt->n_bytes;
+	}
+	yaffs_dump_packed_tags2_tags_only(ptt);
+	yaffs_dump_tags2(t);
+}
+
+void yaffs_unpack_tags2(struct yaffs_ext_tags *t, struct yaffs_packed_tags2 *pt,
+			int tags_ecc)
+{
+	enum yaffs_ecc_result ecc_result = YAFFS_ECC_RESULT_NO_ERROR;
+
+	if (pt->t.seq_number != 0xffffffff && tags_ecc) {
+		/* Chunk is in use and we need to do ECC */
+
+		struct yaffs_ecc_other ecc;
+		int result;
+		yaffs_ecc_calc_other((unsigned char *)&pt->t,
+				sizeof(struct yaffs_packed_tags2_tags_only),
+				&ecc);
+		result =
+		    yaffs_ecc_correct_other((unsigned char *)&pt->t,
+				sizeof(struct yaffs_packed_tags2_tags_only),
+				&pt->ecc, &ecc);
+		switch (result) {
+		case 0:
+			ecc_result = YAFFS_ECC_RESULT_NO_ERROR;
+			break;
+		case 1:
+			ecc_result = YAFFS_ECC_RESULT_FIXED;
+			break;
+		case -1:
+			ecc_result = YAFFS_ECC_RESULT_UNFIXED;
+			break;
+		default:
+			ecc_result = YAFFS_ECC_RESULT_UNKNOWN;
+		}
+	}
+	yaffs_unpack_tags2_tags_only(t, &pt->t);
+
+	t->ecc_result = ecc_result;
+
+	yaffs_dump_packed_tags2(pt);
+	yaffs_dump_tags2(t);
+}
diff --git a/linux-bsp/asm-study/yaffs2/yaffs2/yaffs_packedtags2.h b/linux-bsp/asm-study/yaffs2/yaffs2/yaffs_packedtags2.h
new file mode 100644
index 0000000..675e719
--- /dev/null
+++ b/linux-bsp/asm-study/yaffs2/yaffs2/yaffs_packedtags2.h
@@ -0,0 +1,47 @@
+/*
+ * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
+ *
+ * Copyright (C) 2002-2011 Aleph One Ltd.
+ *   for Toby Churchill Ltd and Brightstar Engineering
+ *
+ * Created by Charles Manning <charles@aleph1.co.uk>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 2.1 as
+ * published by the Free Software Foundation.
+ *
+ * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
+ */
+
+/* This is used to pack YAFFS2 tags, not YAFFS1tags. */
+
+#ifndef __YAFFS_PACKEDTAGS2_H__
+#define __YAFFS_PACKEDTAGS2_H__
+
+#include "yaffs_guts.h"
+#include "yaffs_ecc.h"
+
+struct yaffs_packed_tags2_tags_only {
+	unsigned seq_number;
+	unsigned obj_id;
+	unsigned chunk_id;
+	unsigned n_bytes;
+};
+
+struct yaffs_packed_tags2 {
+	struct yaffs_packed_tags2_tags_only t;
+	struct yaffs_ecc_other ecc;
+};
+
+/* Full packed tags with ECC, used for oob tags */
+void yaffs_pack_tags2(struct yaffs_packed_tags2 *pt,
+		      const struct yaffs_ext_tags *t, int tags_ecc);
+void yaffs_unpack_tags2(struct yaffs_ext_tags *t, struct yaffs_packed_tags2 *pt,
+			int tags_ecc);
+
+/* Only the tags part (no ECC for use with inband tags */
+void yaffs_pack_tags2_tags_only(struct yaffs_packed_tags2_tags_only *pt,
+				const struct yaffs_ext_tags *t);
+void yaffs_unpack_tags2_tags_only(struct yaffs_ext_tags *t,
+				  struct yaffs_packed_tags2_tags_only *pt);
+#endif
diff --git a/linux-bsp/asm-study/yaffs2/yaffs2/yaffs_qsort.c b/linux-bsp/asm-study/yaffs2/yaffs2/yaffs_qsort.c
new file mode 100644
index 0000000..afd1ffa
--- /dev/null
+++ b/linux-bsp/asm-study/yaffs2/yaffs2/yaffs_qsort.c
@@ -0,0 +1,163 @@
+/*
+ * Copyright (c) 1992, 1993
+ *	The Regents of the University of California.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include "yportenv.h"
+/* #include <linux/string.h> */
+
+/*
+ * Qsort routine from Bentley & McIlroy's "Engineering a Sort Function".
+ */
+#define swapcode(TYPE, parmi, parmj, n) do {		\
+	long i = (n) / sizeof(TYPE);			\
+	register TYPE *pi = (TYPE *) (parmi);		\
+	register TYPE *pj = (TYPE *) (parmj);		\
+	do {						\
+		register TYPE	t = *pi;		\
+		*pi++ = *pj;				\
+		*pj++ = t;				\
+	} while (--i > 0);				\
+} while (0)
+
+#define SWAPINIT(a, es) swaptype = ((char *)a - (char *)0) % sizeof(long) || \
+	es % sizeof(long) ? 2 : es == sizeof(long) ? 0 : 1;
+
+static inline void
+swapfunc(char *a, char *b, int n, int swaptype)
+{
+	if (swaptype <= 1)
+		swapcode(long, a, b, n);
+	else
+		swapcode(char, a, b, n);
+}
+
+#define yswap(a, b) do {					\
+	if (swaptype == 0) {				\
+		long t = *(long *)(a);			\
+		*(long *)(a) = *(long *)(b);		\
+		*(long *)(b) = t;			\
+	} else						\
+		swapfunc(a, b, es, swaptype);		\
+} while (0)
+
+#define vecswap(a, b, n)	if ((n) > 0) swapfunc(a, b, n, swaptype)
+
+static inline char *
+med3(char *a, char *b, char *c, int (*cmp)(const void *, const void *))
+{
+	return cmp(a, b) < 0 ?
+		(cmp(b, c) < 0 ? b : (cmp(a, c) < 0 ? c : a))
+		: (cmp(b, c) > 0 ? b : (cmp(a, c) < 0 ? a : c));
+}
+
+#ifndef min
+#define min(a, b) (((a) < (b)) ? (a) : (b))
+#endif
+
+void
+yaffs_qsort(void *aa, size_t n, size_t es,
+	int (*cmp)(const void *, const void *))
+{
+	char *pa, *pb, *pc, *pd, *pl, *pm, *pn;
+	int d, r, swaptype, swap_cnt;
+	register char *a = aa;
+
+loop:	SWAPINIT(a, es);
+	swap_cnt = 0;
+	if (n < 7) {
+		for (pm = (char *)a + es; pm < (char *) a + n * es; pm += es)
+			for (pl = pm; pl > (char *) a && cmp(pl - es, pl) > 0;
+			     pl -= es)
+				yswap(pl, pl - es);
+		return;
+	}
+	pm = (char *)a + (n / 2) * es;
+	if (n > 7) {
+		pl = (char *)a;
+		pn = (char *)a + (n - 1) * es;
+		if (n > 40) {
+			d = (n / 8) * es;
+			pl = med3(pl, pl + d, pl + 2 * d, cmp);
+			pm = med3(pm - d, pm, pm + d, cmp);
+			pn = med3(pn - 2 * d, pn - d, pn, cmp);
+		}
+		pm = med3(pl, pm, pn, cmp);
+	}
+	yswap(a, pm);
+	pa = pb = (char *)a + es;
+
+	pc = pd = (char *)a + (n - 1) * es;
+	for (;;) {
+		while (pb <= pc && (r = cmp(pb, a)) <= 0) {
+			if (r == 0) {
+				swap_cnt = 1;
+				yswap(pa, pb);
+				pa += es;
+			}
+			pb += es;
+		}
+		while (pb <= pc && (r = cmp(pc, a)) >= 0) {
+			if (r == 0) {
+				swap_cnt = 1;
+				yswap(pc, pd);
+				pd -= es;
+			}
+			pc -= es;
+		}
+		if (pb > pc)
+			break;
+		yswap(pb, pc);
+		swap_cnt = 1;
+		pb += es;
+		pc -= es;
+	}
+	if (swap_cnt == 0) {  /* Switch to insertion sort */
+		for (pm = (char *) a + es; pm < (char *) a + n * es; pm += es)
+			for (pl = pm; pl > (char *) a && cmp(pl - es, pl) > 0;
+			     pl -= es)
+				yswap(pl, pl - es);
+		return;
+	}
+
+	pn = (char *)a + n * es;
+	r = min(pa - (char *)a, pb - pa);
+	vecswap(a, pb - r, r);
+	r = min((long)(pd - pc), (long)(pn - pd - es));
+	vecswap(pb, pn - r, r);
+	r = pb - pa;
+	if (r > es)
+		yaffs_qsort(a, r / es, es, cmp);
+	r = pd - pc;
+	if (r > es) {
+		/* Iterate rather than recurse to save stack space */
+		a = pn - r;
+		n = r / es;
+		goto loop;
+	}
+/*		yaffs_qsort(pn - r, r / es, es, cmp);*/
+}
diff --git a/linux-bsp/asm-study/yaffs2/yaffs2/yaffs_summary.c b/linux-bsp/asm-study/yaffs2/yaffs2/yaffs_summary.c
new file mode 100644
index 0000000..6f3c783
--- /dev/null
+++ b/linux-bsp/asm-study/yaffs2/yaffs2/yaffs_summary.c
@@ -0,0 +1,313 @@
+/*
+ * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
+ *
+ * Copyright (C) 2002-2011 Aleph One Ltd.
+ *   for Toby Churchill Ltd and Brightstar Engineering
+ *
+ * Created by Charles Manning <charles@aleph1.co.uk>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+/* Summaries write the useful part of the tags for the chunks in a block into an
+ * an array which is written to the last n chunks of the block.
+ * Reading the summaries gives all the tags for the block in one read. Much
+ * faster.
+ *
+ * Chunks holding summaries are marked with tags making it look like
+ * they are part of a fake file.
+ *
+ * The summary could also be used during gc.
+ *
+ */
+
+#include "yaffs_summary.h"
+#include "yaffs_packedtags2.h"
+#include "yaffs_nand.h"
+#include "yaffs_getblockinfo.h"
+#include "yaffs_bitmap.h"
+
+/*
+ * The summary is built up in an array of summary tags.
+ * This gets written to the last one or two (maybe more) chunks in a block.
+ * A summary header is written as the first part of each chunk of summary data.
+ * The summary header must match or the summary is rejected.
+ */
+
+/* Summary tags don't need the sequence number because that is redundant. */
+struct yaffs_summary_tags {
+	unsigned obj_id;
+	unsigned chunk_id;
+	unsigned n_bytes;
+};
+
+/* Summary header */
+struct yaffs_summary_header {
+	unsigned version;	/* Must match current version */
+	unsigned block;		/* Must be this block */
+	unsigned seq;		/* Must be this sequence number */
+	unsigned sum;		/* Just add up all the bytes in the tags */
+};
+
+
+static void yaffs_summary_clear(struct yaffs_dev *dev)
+{
+	if (!dev->sum_tags)
+		return;
+	memset(dev->sum_tags, 0, dev->chunks_per_summary *
+		sizeof(struct yaffs_summary_tags));
+}
+
+
+void yaffs_summary_deinit(struct yaffs_dev *dev)
+{
+	kfree(dev->sum_tags);
+	dev->sum_tags = NULL;
+	kfree(dev->gc_sum_tags);
+	dev->gc_sum_tags = NULL;
+	dev->chunks_per_summary = 0;
+}
+
+int yaffs_summary_init(struct yaffs_dev *dev)
+{
+	int sum_bytes;
+	int chunks_used; /* Number of chunks used by summary */
+	int sum_tags_bytes;
+
+	sum_bytes = dev->param.chunks_per_block *
+			sizeof(struct yaffs_summary_tags);
+
+	chunks_used = (sum_bytes + dev->data_bytes_per_chunk - 1)/
+			(dev->data_bytes_per_chunk -
+				sizeof(struct yaffs_summary_header));
+
+	dev->chunks_per_summary = dev->param.chunks_per_block - chunks_used;
+	sum_tags_bytes = sizeof(struct yaffs_summary_tags) *
+				dev->chunks_per_summary;
+	dev->sum_tags = kmalloc(sum_tags_bytes, GFP_NOFS);
+	dev->gc_sum_tags = kmalloc(sum_tags_bytes, GFP_NOFS);
+	if (!dev->sum_tags || !dev->gc_sum_tags) {
+		yaffs_summary_deinit(dev);
+		return YAFFS_FAIL;
+	}
+
+	yaffs_summary_clear(dev);
+
+	return YAFFS_OK;
+}
+
+static unsigned yaffs_summary_sum(struct yaffs_dev *dev)
+{
+	u8 *sum_buffer = (u8 *)dev->sum_tags;
+	int i;
+	unsigned sum = 0;
+
+	i = sizeof(struct yaffs_summary_tags) *
+				dev->chunks_per_summary;
+	while (i > 0) {
+		sum += *sum_buffer;
+		sum_buffer++;
+		i--;
+	}
+
+	return sum;
+}
+
+static int yaffs_summary_write(struct yaffs_dev *dev, int blk)
+{
+	struct yaffs_ext_tags tags;
+	u8 *buffer;
+	u8 *sum_buffer = (u8 *)dev->sum_tags;
+	int n_bytes;
+	int chunk_in_nand;
+	int chunk_in_block;
+	int result;
+	int this_tx;
+	struct yaffs_summary_header hdr;
+	int sum_bytes_per_chunk = dev->data_bytes_per_chunk - sizeof(hdr);
+	struct yaffs_block_info *bi = yaffs_get_block_info(dev, blk);
+
+	buffer = yaffs_get_temp_buffer(dev);
+	n_bytes = sizeof(struct yaffs_summary_tags) *
+				dev->chunks_per_summary;
+	memset(&tags, 0, sizeof(struct yaffs_ext_tags));
+	tags.obj_id = YAFFS_OBJECTID_SUMMARY;
+	tags.chunk_id = 1;
+	chunk_in_block = dev->chunks_per_summary;
+	chunk_in_nand = dev->alloc_block * dev->param.chunks_per_block +
+						dev->chunks_per_summary;
+	hdr.version = YAFFS_SUMMARY_VERSION;
+	hdr.block = blk;
+	hdr.seq = bi->seq_number;
+	hdr.sum = yaffs_summary_sum(dev);
+
+	do {
+		this_tx = n_bytes;
+		if (this_tx > sum_bytes_per_chunk)
+			this_tx = sum_bytes_per_chunk;
+		memcpy(buffer, &hdr, sizeof(hdr));
+		memcpy(buffer + sizeof(hdr), sum_buffer, this_tx);
+		tags.n_bytes = this_tx + sizeof(hdr);
+		result = yaffs_wr_chunk_tags_nand(dev, chunk_in_nand,
+						buffer, &tags);
+
+		if (result != YAFFS_OK)
+			break;
+		yaffs_set_chunk_bit(dev, blk, chunk_in_block);
+		bi->pages_in_use++;
+		dev->n_free_chunks--;
+
+		n_bytes -= this_tx;
+		sum_buffer += this_tx;
+		chunk_in_nand++;
+		chunk_in_block++;
+		tags.chunk_id++;
+	} while (result == YAFFS_OK && n_bytes > 0);
+	yaffs_release_temp_buffer(dev, buffer);
+
+
+	if (result == YAFFS_OK)
+		bi->has_summary = 1;
+
+
+	return result;
+}
+
+int yaffs_summary_read(struct yaffs_dev *dev,
+			struct yaffs_summary_tags *st,
+			int blk)
+{
+	struct yaffs_ext_tags tags;
+	u8 *buffer;
+	u8 *sum_buffer = (u8 *)st;
+	int n_bytes;
+	int chunk_id;
+	int chunk_in_nand;
+	int chunk_in_block;
+	int result;
+	int this_tx;
+	struct yaffs_summary_header hdr;
+	struct yaffs_block_info *bi = yaffs_get_block_info(dev, blk);
+	int sum_bytes_per_chunk = dev->data_bytes_per_chunk - sizeof(hdr);
+	int sum_tags_bytes;
+
+	sum_tags_bytes = sizeof(struct yaffs_summary_tags) *
+				dev->chunks_per_summary;
+	buffer = yaffs_get_temp_buffer(dev);
+	n_bytes = sizeof(struct yaffs_summary_tags) * dev->chunks_per_summary;
+	chunk_in_block = dev->chunks_per_summary;
+	chunk_in_nand = blk * dev->param.chunks_per_block +
+							dev->chunks_per_summary;
+	chunk_id = 1;
+	do {
+		this_tx = n_bytes;
+		if (this_tx > sum_bytes_per_chunk)
+			this_tx = sum_bytes_per_chunk;
+		result = yaffs_rd_chunk_tags_nand(dev, chunk_in_nand,
+						buffer, &tags);
+
+		if (tags.chunk_id != chunk_id ||
+			tags.obj_id != YAFFS_OBJECTID_SUMMARY ||
+			tags.chunk_used == 0 ||
+			tags.ecc_result > YAFFS_ECC_RESULT_FIXED ||
+			tags.n_bytes != (this_tx + sizeof(hdr)))
+				result = YAFFS_FAIL;
+		if (result != YAFFS_OK)
+			break;
+
+		if (st == dev->sum_tags) {
+			/* If we're scanning then update the block info */
+			yaffs_set_chunk_bit(dev, blk, chunk_in_block);
+			bi->pages_in_use++;
+		}
+		memcpy(&hdr, buffer, sizeof(hdr));
+		memcpy(sum_buffer, buffer + sizeof(hdr), this_tx);
+		n_bytes -= this_tx;
+		sum_buffer += this_tx;
+		chunk_in_nand++;
+		chunk_in_block++;
+		chunk_id++;
+	} while (result == YAFFS_OK && n_bytes > 0);
+	yaffs_release_temp_buffer(dev, buffer);
+
+	if (result == YAFFS_OK) {
+		/* Verify header */
+		if (hdr.version != YAFFS_SUMMARY_VERSION ||
+		    hdr.block != blk ||
+		    hdr.seq != bi->seq_number ||
+		    hdr.sum != yaffs_summary_sum(dev))
+			result = YAFFS_FAIL;
+	}
+
+	if (st == dev->sum_tags && result == YAFFS_OK)
+		bi->has_summary = 1;
+
+	return result;
+}
+
+int yaffs_summary_add(struct yaffs_dev *dev,
+			struct yaffs_ext_tags *tags,
+			int chunk_in_nand)
+{
+	struct yaffs_packed_tags2_tags_only tags_only;
+	struct yaffs_summary_tags *sum_tags;
+	int block_in_nand = chunk_in_nand / dev->param.chunks_per_block;
+	int chunk_in_block = chunk_in_nand % dev->param.chunks_per_block;
+
+	if (!dev->sum_tags)
+		return YAFFS_OK;
+
+	if (chunk_in_block >= 0 && chunk_in_block < dev->chunks_per_summary) {
+		yaffs_pack_tags2_tags_only(&tags_only, tags);
+		sum_tags = &dev->sum_tags[chunk_in_block];
+		sum_tags->chunk_id = tags_only.chunk_id;
+		sum_tags->n_bytes = tags_only.n_bytes;
+		sum_tags->obj_id = tags_only.obj_id;
+
+		if (chunk_in_block == dev->chunks_per_summary - 1) {
+			/* Time to write out the summary */
+			yaffs_summary_write(dev, block_in_nand);
+			yaffs_summary_clear(dev);
+			yaffs_skip_rest_of_block(dev);
+		}
+	}
+	return YAFFS_OK;
+}
+
+int yaffs_summary_fetch(struct yaffs_dev *dev,
+			struct yaffs_ext_tags *tags,
+			int chunk_in_block)
+{
+	struct yaffs_packed_tags2_tags_only tags_only;
+	struct yaffs_summary_tags *sum_tags;
+	if (chunk_in_block >= 0 && chunk_in_block < dev->chunks_per_summary) {
+		sum_tags = &dev->sum_tags[chunk_in_block];
+		tags_only.chunk_id = sum_tags->chunk_id;
+		tags_only.n_bytes = sum_tags->n_bytes;
+		tags_only.obj_id = sum_tags->obj_id;
+		yaffs_unpack_tags2_tags_only(tags, &tags_only);
+		return YAFFS_OK;
+	}
+	return YAFFS_FAIL;
+}
+
+void yaffs_summary_gc(struct yaffs_dev *dev, int blk)
+{
+	struct yaffs_block_info *bi = yaffs_get_block_info(dev, blk);
+	int i;
+
+	if (!bi->has_summary)
+		return;
+
+	for (i = dev->chunks_per_summary;
+	     i < dev->param.chunks_per_block;
+	     i++) {
+		if (yaffs_check_chunk_bit(dev, blk, i)) {
+			yaffs_clear_chunk_bit(dev, blk, i);
+			bi->pages_in_use--;
+			dev->n_free_chunks++;
+		}
+	}
+}
diff --git a/linux-bsp/asm-study/yaffs2/yaffs2/yaffs_summary.h b/linux-bsp/asm-study/yaffs2/yaffs2/yaffs_summary.h
new file mode 100644
index 0000000..be141d0
--- /dev/null
+++ b/linux-bsp/asm-study/yaffs2/yaffs2/yaffs_summary.h
@@ -0,0 +1,37 @@
+/*
+ * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
+ *
+ * Copyright (C) 2002-2011 Aleph One Ltd.
+ *   for Toby Churchill Ltd and Brightstar Engineering
+ *
+ * Created by Charles Manning <charles@aleph1.co.uk>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 2.1 as
+ * published by the Free Software Foundation.
+ *
+ * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
+ */
+
+#ifndef __YAFFS_SUMMARY_H__
+#define __YAFFS_SUMMARY_H__
+
+#include "yaffs_packedtags2.h"
+
+
+int yaffs_summary_init(struct yaffs_dev *dev);
+void yaffs_summary_deinit(struct yaffs_dev *dev);
+
+int yaffs_summary_add(struct yaffs_dev *dev,
+			struct yaffs_ext_tags *tags,
+			int chunk_in_block);
+int yaffs_summary_fetch(struct yaffs_dev *dev,
+			struct yaffs_ext_tags *tags,
+			int chunk_in_block);
+int yaffs_summary_read(struct yaffs_dev *dev,
+			struct yaffs_summary_tags *st,
+			int blk);
+void yaffs_summary_gc(struct yaffs_dev *dev, int blk);
+
+
+#endif
diff --git a/linux-bsp/asm-study/yaffs2/yaffs2/yaffs_tagscompat.c b/linux-bsp/asm-study/yaffs2/yaffs2/yaffs_tagscompat.c
new file mode 100644
index 0000000..32ba11f
--- /dev/null
+++ b/linux-bsp/asm-study/yaffs2/yaffs2/yaffs_tagscompat.c
@@ -0,0 +1,407 @@
+/*
+ * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
+ *
+ * Copyright (C) 2002-2011 Aleph One Ltd.
+ *   for Toby Churchill Ltd and Brightstar Engineering
+ *
+ * Created by Charles Manning <charles@aleph1.co.uk>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include "yaffs_guts.h"
+#include "yaffs_tagscompat.h"
+#include "yaffs_ecc.h"
+#include "yaffs_getblockinfo.h"
+#include "yaffs_trace.h"
+
+static void yaffs_handle_rd_data_error(struct yaffs_dev *dev, int nand_chunk);
+
+
+/********** Tags ECC calculations  *********/
+
+static void yaffs_calc_ecc(const u8 *data, struct yaffs_spare *spare)
+{
+	yaffs_ecc_calc(data, spare->ecc1);
+	yaffs_ecc_calc(&data[256], spare->ecc2);
+}
+
+void yaffs_calc_tags_ecc(struct yaffs_tags *tags)
+{
+	/* Calculate an ecc */
+	unsigned char *b = ((union yaffs_tags_union *)tags)->as_bytes;
+	unsigned i, j;
+	unsigned ecc = 0;
+	unsigned bit = 0;
+
+	tags->ecc = 0;
+
+	for (i = 0; i < 8; i++) {
+		for (j = 1; j & 0xff; j <<= 1) {
+			bit++;
+			if (b[i] & j)
+				ecc ^= bit;
+		}
+	}
+	tags->ecc = ecc;
+}
+
+int yaffs_check_tags_ecc(struct yaffs_tags *tags)
+{
+	unsigned ecc = tags->ecc;
+
+	yaffs_calc_tags_ecc(tags);
+
+	ecc ^= tags->ecc;
+
+	if (ecc && ecc <= 64) {
+		/* TODO: Handle the failure better. Retire? */
+		unsigned char *b = ((union yaffs_tags_union *)tags)->as_bytes;
+
+		ecc--;
+
+		b[ecc / 8] ^= (1 << (ecc & 7));
+
+		/* Now recvalc the ecc */
+		yaffs_calc_tags_ecc(tags);
+
+		return 1;	/* recovered error */
+	} else if (ecc) {
+		/* Wierd ecc failure value */
+		/* TODO Need to do somethiong here */
+		return -1;	/* unrecovered error */
+	}
+	return 0;
+}
+
+/********** Tags **********/
+
+static void yaffs_load_tags_to_spare(struct yaffs_spare *spare_ptr,
+				     struct yaffs_tags *tags_ptr)
+{
+	union yaffs_tags_union *tu = (union yaffs_tags_union *)tags_ptr;
+
+	yaffs_calc_tags_ecc(tags_ptr);
+
+	spare_ptr->tb0 = tu->as_bytes[0];
+	spare_ptr->tb1 = tu->as_bytes[1];
+	spare_ptr->tb2 = tu->as_bytes[2];
+	spare_ptr->tb3 = tu->as_bytes[3];
+	spare_ptr->tb4 = tu->as_bytes[4];
+	spare_ptr->tb5 = tu->as_bytes[5];
+	spare_ptr->tb6 = tu->as_bytes[6];
+	spare_ptr->tb7 = tu->as_bytes[7];
+}
+
+static void yaffs_get_tags_from_spare(struct yaffs_dev *dev,
+				      struct yaffs_spare *spare_ptr,
+				      struct yaffs_tags *tags_ptr)
+{
+	union yaffs_tags_union *tu = (union yaffs_tags_union *)tags_ptr;
+	int result;
+
+	tu->as_bytes[0] = spare_ptr->tb0;
+	tu->as_bytes[1] = spare_ptr->tb1;
+	tu->as_bytes[2] = spare_ptr->tb2;
+	tu->as_bytes[3] = spare_ptr->tb3;
+	tu->as_bytes[4] = spare_ptr->tb4;
+	tu->as_bytes[5] = spare_ptr->tb5;
+	tu->as_bytes[6] = spare_ptr->tb6;
+	tu->as_bytes[7] = spare_ptr->tb7;
+
+	result = yaffs_check_tags_ecc(tags_ptr);
+	if (result > 0)
+		dev->n_tags_ecc_fixed++;
+	else if (result < 0)
+		dev->n_tags_ecc_unfixed++;
+}
+
+static void yaffs_spare_init(struct yaffs_spare *spare)
+{
+	memset(spare, 0xff, sizeof(struct yaffs_spare));
+}
+
+static int yaffs_wr_nand(struct yaffs_dev *dev,
+			 int nand_chunk, const u8 *data,
+			 struct yaffs_spare *spare)
+{
+	if (nand_chunk < dev->param.start_block * dev->param.chunks_per_block) {
+		yaffs_trace(YAFFS_TRACE_ERROR,
+			"**>> yaffs chunk %d is not valid",
+			nand_chunk);
+		return YAFFS_FAIL;
+	}
+
+	return dev->param.write_chunk_fn(dev, nand_chunk, data, spare);
+}
+
+static int yaffs_rd_chunk_nand(struct yaffs_dev *dev,
+			       int nand_chunk,
+			       u8 *data,
+			       struct yaffs_spare *spare,
+			       enum yaffs_ecc_result *ecc_result,
+			       int correct_errors)
+{
+	int ret_val;
+	struct yaffs_spare local_spare;
+
+	if (!spare) {
+		/* If we don't have a real spare, then we use a local one. */
+		/* Need this for the calculation of the ecc */
+		spare = &local_spare;
+	}
+
+	if (!dev->param.use_nand_ecc) {
+		ret_val =
+		    dev->param.read_chunk_fn(dev, nand_chunk, data, spare);
+		if (data && correct_errors) {
+			/* Do ECC correction */
+			/* Todo handle any errors */
+			int ecc_result1, ecc_result2;
+			u8 calc_ecc[3];
+
+			yaffs_ecc_calc(data, calc_ecc);
+			ecc_result1 =
+			    yaffs_ecc_correct(data, spare->ecc1, calc_ecc);
+			yaffs_ecc_calc(&data[256], calc_ecc);
+			ecc_result2 =
+			    yaffs_ecc_correct(&data[256], spare->ecc2,
+					      calc_ecc);
+
+			if (ecc_result1 > 0) {
+				yaffs_trace(YAFFS_TRACE_ERROR,
+					"**>>yaffs ecc error fix performed on chunk %d:0",
+					nand_chunk);
+				dev->n_ecc_fixed++;
+			} else if (ecc_result1 < 0) {
+				yaffs_trace(YAFFS_TRACE_ERROR,
+					"**>>yaffs ecc error unfixed on chunk %d:0",
+					nand_chunk);
+				dev->n_ecc_unfixed++;
+			}
+
+			if (ecc_result2 > 0) {
+				yaffs_trace(YAFFS_TRACE_ERROR,
+					"**>>yaffs ecc error fix performed on chunk %d:1",
+					nand_chunk);
+				dev->n_ecc_fixed++;
+			} else if (ecc_result2 < 0) {
+				yaffs_trace(YAFFS_TRACE_ERROR,
+					"**>>yaffs ecc error unfixed on chunk %d:1",
+					nand_chunk);
+				dev->n_ecc_unfixed++;
+			}
+
+			if (ecc_result1 || ecc_result2) {
+				/* We had a data problem on this page */
+				yaffs_handle_rd_data_error(dev, nand_chunk);
+			}
+
+			if (ecc_result1 < 0 || ecc_result2 < 0)
+				*ecc_result = YAFFS_ECC_RESULT_UNFIXED;
+			else if (ecc_result1 > 0 || ecc_result2 > 0)
+				*ecc_result = YAFFS_ECC_RESULT_FIXED;
+			else
+				*ecc_result = YAFFS_ECC_RESULT_NO_ERROR;
+		}
+	} else {
+		/* Must allocate enough memory for spare+2*sizeof(int) */
+		/* for ecc results from device. */
+		struct yaffs_nand_spare nspare;
+
+		memset(&nspare, 0, sizeof(nspare));
+
+		ret_val = dev->param.read_chunk_fn(dev, nand_chunk, data,
+						   (struct yaffs_spare *)
+						   &nspare);
+		memcpy(spare, &nspare, sizeof(struct yaffs_spare));
+		if (data && correct_errors) {
+			if (nspare.eccres1 > 0) {
+				yaffs_trace(YAFFS_TRACE_ERROR,
+					"**>>mtd ecc error fix performed on chunk %d:0",
+					nand_chunk);
+			} else if (nspare.eccres1 < 0) {
+				yaffs_trace(YAFFS_TRACE_ERROR,
+					"**>>mtd ecc error unfixed on chunk %d:0",
+					nand_chunk);
+			}
+
+			if (nspare.eccres2 > 0) {
+				yaffs_trace(YAFFS_TRACE_ERROR,
+					"**>>mtd ecc error fix performed on chunk %d:1",
+					nand_chunk);
+			} else if (nspare.eccres2 < 0) {
+				yaffs_trace(YAFFS_TRACE_ERROR,
+					"**>>mtd ecc error unfixed on chunk %d:1",
+					nand_chunk);
+			}
+
+			if (nspare.eccres1 || nspare.eccres2) {
+				/* We had a data problem on this page */
+				yaffs_handle_rd_data_error(dev, nand_chunk);
+			}
+
+			if (nspare.eccres1 < 0 || nspare.eccres2 < 0)
+				*ecc_result = YAFFS_ECC_RESULT_UNFIXED;
+			else if (nspare.eccres1 > 0 || nspare.eccres2 > 0)
+				*ecc_result = YAFFS_ECC_RESULT_FIXED;
+			else
+				*ecc_result = YAFFS_ECC_RESULT_NO_ERROR;
+
+		}
+	}
+	return ret_val;
+}
+
+/*
+ * Functions for robustisizing
+ */
+
+static void yaffs_handle_rd_data_error(struct yaffs_dev *dev, int nand_chunk)
+{
+	int flash_block = nand_chunk / dev->param.chunks_per_block;
+
+	/* Mark the block for retirement */
+	yaffs_get_block_info(dev, flash_block + dev->block_offset)->
+		needs_retiring = 1;
+	yaffs_trace(YAFFS_TRACE_ERROR | YAFFS_TRACE_BAD_BLOCKS,
+		"**>>Block %d marked for retirement",
+		flash_block);
+
+	/* TODO:
+	 * Just do a garbage collection on the affected block
+	 * then retire the block
+	 * NB recursion
+	 */
+}
+
+int yaffs_tags_compat_wr(struct yaffs_dev *dev,
+			 int nand_chunk,
+			 const u8 *data, const struct yaffs_ext_tags *ext_tags)
+{
+	struct yaffs_spare spare;
+	struct yaffs_tags tags;
+
+	yaffs_spare_init(&spare);
+
+	if (ext_tags->is_deleted)
+		spare.page_status = 0;
+	else {
+		tags.obj_id = ext_tags->obj_id;
+		tags.chunk_id = ext_tags->chunk_id;
+
+		tags.n_bytes_lsb = ext_tags->n_bytes & (1024 - 1);
+
+		if (dev->data_bytes_per_chunk >= 1024)
+			tags.n_bytes_msb = (ext_tags->n_bytes >> 10) & 3;
+		else
+			tags.n_bytes_msb = 3;
+
+		tags.serial_number = ext_tags->serial_number;
+
+		if (!dev->param.use_nand_ecc && data)
+			yaffs_calc_ecc(data, &spare);
+
+		yaffs_load_tags_to_spare(&spare, &tags);
+	}
+	return yaffs_wr_nand(dev, nand_chunk, data, &spare);
+}
+
+int yaffs_tags_compat_rd(struct yaffs_dev *dev,
+			 int nand_chunk,
+			 u8 *data, struct yaffs_ext_tags *ext_tags)
+{
+	struct yaffs_spare spare;
+	struct yaffs_tags tags;
+	enum yaffs_ecc_result ecc_result = YAFFS_ECC_RESULT_UNKNOWN;
+	static struct yaffs_spare spare_ff;
+	static int init;
+	int deleted;
+
+	if (!init) {
+		memset(&spare_ff, 0xff, sizeof(spare_ff));
+		init = 1;
+	}
+
+	if (!yaffs_rd_chunk_nand(dev, nand_chunk,
+					data, &spare, &ecc_result, 1))
+		return YAFFS_FAIL;
+
+	/* ext_tags may be NULL */
+	if (!ext_tags)
+		return YAFFS_OK;
+
+	deleted = (hweight8(spare.page_status) < 7) ? 1 : 0;
+
+	ext_tags->is_deleted = deleted;
+	ext_tags->ecc_result = ecc_result;
+	ext_tags->block_bad = 0;	/* We're reading it */
+	/* therefore it is not a bad block */
+	ext_tags->chunk_used =
+		memcmp(&spare_ff, &spare, sizeof(spare_ff)) ? 1 : 0;
+
+	if (ext_tags->chunk_used) {
+		yaffs_get_tags_from_spare(dev, &spare, &tags);
+		ext_tags->obj_id = tags.obj_id;
+		ext_tags->chunk_id = tags.chunk_id;
+		ext_tags->n_bytes = tags.n_bytes_lsb;
+
+		if (dev->data_bytes_per_chunk >= 1024)
+			ext_tags->n_bytes |=
+				(((unsigned)tags.n_bytes_msb) << 10);
+
+		ext_tags->serial_number = tags.serial_number;
+	}
+
+	return YAFFS_OK;
+}
+
+int yaffs_tags_compat_mark_bad(struct yaffs_dev *dev, int flash_block)
+{
+	struct yaffs_spare spare;
+
+	memset(&spare, 0xff, sizeof(struct yaffs_spare));
+
+	spare.block_status = 'Y';
+
+	yaffs_wr_nand(dev, flash_block * dev->param.chunks_per_block, NULL,
+		      &spare);
+	yaffs_wr_nand(dev, flash_block * dev->param.chunks_per_block + 1,
+		      NULL, &spare);
+
+	return YAFFS_OK;
+}
+
+int yaffs_tags_compat_query_block(struct yaffs_dev *dev,
+				  int block_no,
+				  enum yaffs_block_state *state,
+				  u32 *seq_number)
+{
+	struct yaffs_spare spare0, spare1;
+	static struct yaffs_spare spare_ff;
+	static int init;
+	enum yaffs_ecc_result dummy;
+
+	if (!init) {
+		memset(&spare_ff, 0xff, sizeof(spare_ff));
+		init = 1;
+	}
+
+	*seq_number = 0;
+
+	yaffs_rd_chunk_nand(dev, block_no * dev->param.chunks_per_block, NULL,
+			    &spare0, &dummy, 1);
+	yaffs_rd_chunk_nand(dev, block_no * dev->param.chunks_per_block + 1,
+			    NULL, &spare1, &dummy, 1);
+
+	if (hweight8(spare0.block_status & spare1.block_status) < 7)
+		*state = YAFFS_BLOCK_STATE_DEAD;
+	else if (memcmp(&spare_ff, &spare0, sizeof(spare_ff)) == 0)
+		*state = YAFFS_BLOCK_STATE_EMPTY;
+	else
+		*state = YAFFS_BLOCK_STATE_NEEDS_SCAN;
+
+	return YAFFS_OK;
+}
diff --git a/linux-bsp/asm-study/yaffs2/yaffs2/yaffs_tagscompat.h b/linux-bsp/asm-study/yaffs2/yaffs2/yaffs_tagscompat.h
new file mode 100644
index 0000000..b3c6655
--- /dev/null
+++ b/linux-bsp/asm-study/yaffs2/yaffs2/yaffs_tagscompat.h
@@ -0,0 +1,36 @@
+/*
+ * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
+ *
+ * Copyright (C) 2002-2011 Aleph One Ltd.
+ *   for Toby Churchill Ltd and Brightstar Engineering
+ *
+ * Created by Charles Manning <charles@aleph1.co.uk>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 2.1 as
+ * published by the Free Software Foundation.
+ *
+ * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
+ */
+
+#ifndef __YAFFS_TAGSCOMPAT_H__
+#define __YAFFS_TAGSCOMPAT_H__
+
+#include "yaffs_guts.h"
+int yaffs_tags_compat_wr(struct yaffs_dev *dev,
+			 int nand_chunk,
+			 const u8 *data, const struct yaffs_ext_tags *tags);
+int yaffs_tags_compat_rd(struct yaffs_dev *dev,
+			 int nand_chunk,
+			 u8 *data, struct yaffs_ext_tags *tags);
+int yaffs_tags_compat_mark_bad(struct yaffs_dev *dev, int block_no);
+int yaffs_tags_compat_query_block(struct yaffs_dev *dev,
+				  int block_no,
+				  enum yaffs_block_state *state,
+				  u32 *seq_number);
+
+void yaffs_calc_tags_ecc(struct yaffs_tags *tags);
+int yaffs_check_tags_ecc(struct yaffs_tags *tags);
+int yaffs_count_bits(u8 byte);
+
+#endif
diff --git a/linux-bsp/asm-study/yaffs2/yaffs2/yaffs_trace.h b/linux-bsp/asm-study/yaffs2/yaffs2/yaffs_trace.h
new file mode 100644
index 0000000..fd26054
--- /dev/null
+++ b/linux-bsp/asm-study/yaffs2/yaffs2/yaffs_trace.h
@@ -0,0 +1,57 @@
+/*
+ * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
+ *
+ * Copyright (C) 2002-2011 Aleph One Ltd.
+ *   for Toby Churchill Ltd and Brightstar Engineering
+ *
+ * Created by Charles Manning <charles@aleph1.co.uk>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 2.1 as
+ * published by the Free Software Foundation.
+ *
+ * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
+ */
+
+#ifndef __YTRACE_H__
+#define __YTRACE_H__
+
+extern unsigned int yaffs_trace_mask;
+extern unsigned int yaffs_wr_attempts;
+
+/*
+ * Tracing flags.
+ * The flags masked in YAFFS_TRACE_ALWAYS are always traced.
+ */
+
+#define YAFFS_TRACE_OS			0x00000002
+#define YAFFS_TRACE_ALLOCATE		0x00000004
+#define YAFFS_TRACE_SCAN		0x00000008
+#define YAFFS_TRACE_BAD_BLOCKS		0x00000010
+#define YAFFS_TRACE_ERASE		0x00000020
+#define YAFFS_TRACE_GC			0x00000040
+#define YAFFS_TRACE_WRITE		0x00000080
+#define YAFFS_TRACE_TRACING		0x00000100
+#define YAFFS_TRACE_DELETION		0x00000200
+#define YAFFS_TRACE_BUFFERS		0x00000400
+#define YAFFS_TRACE_NANDACCESS		0x00000800
+#define YAFFS_TRACE_GC_DETAIL		0x00001000
+#define YAFFS_TRACE_SCAN_DEBUG		0x00002000
+#define YAFFS_TRACE_MTD			0x00004000
+#define YAFFS_TRACE_CHECKPOINT		0x00008000
+
+#define YAFFS_TRACE_VERIFY		0x00010000
+#define YAFFS_TRACE_VERIFY_NAND		0x00020000
+#define YAFFS_TRACE_VERIFY_FULL		0x00040000
+#define YAFFS_TRACE_VERIFY_ALL		0x000f0000
+
+#define YAFFS_TRACE_SYNC		0x00100000
+#define YAFFS_TRACE_BACKGROUND		0x00200000
+#define YAFFS_TRACE_LOCK		0x00400000
+#define YAFFS_TRACE_MOUNT		0x00800000
+
+#define YAFFS_TRACE_ERROR		0x40000000
+#define YAFFS_TRACE_BUG			0x80000000
+#define YAFFS_TRACE_ALWAYS		0xf0000000
+
+#endif
diff --git a/linux-bsp/asm-study/yaffs2/yaffs2/yaffs_verify.c b/linux-bsp/asm-study/yaffs2/yaffs2/yaffs_verify.c
new file mode 100644
index 0000000..e8f2f0a
--- /dev/null
+++ b/linux-bsp/asm-study/yaffs2/yaffs2/yaffs_verify.c
@@ -0,0 +1,529 @@
+/*
+ * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
+ *
+ * Copyright (C) 2002-2011 Aleph One Ltd.
+ *   for Toby Churchill Ltd and Brightstar Engineering
+ *
+ * Created by Charles Manning <charles@aleph1.co.uk>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include "yaffs_verify.h"
+#include "yaffs_trace.h"
+#include "yaffs_bitmap.h"
+#include "yaffs_getblockinfo.h"
+#include "yaffs_nand.h"
+
+int yaffs_skip_verification(struct yaffs_dev *dev)
+{
+	(void) dev;
+	return !(yaffs_trace_mask &
+		 (YAFFS_TRACE_VERIFY | YAFFS_TRACE_VERIFY_FULL));
+}
+
+static int yaffs_skip_full_verification(struct yaffs_dev *dev)
+{
+	(void) dev;
+	return !(yaffs_trace_mask & (YAFFS_TRACE_VERIFY_FULL));
+}
+
+static int yaffs_skip_nand_verification(struct yaffs_dev *dev)
+{
+	(void) dev;
+	return !(yaffs_trace_mask & (YAFFS_TRACE_VERIFY_NAND));
+}
+
+static const char * const block_state_name[] = {
+	"Unknown",
+	"Needs scan",
+	"Scanning",
+	"Empty",
+	"Allocating",
+	"Full",
+	"Dirty",
+	"Checkpoint",
+	"Collecting",
+	"Dead"
+};
+
+void yaffs_verify_blk(struct yaffs_dev *dev, struct yaffs_block_info *bi, int n)
+{
+	int actually_used;
+	int in_use;
+
+	if (yaffs_skip_verification(dev))
+		return;
+
+	/* Report illegal runtime states */
+	if (bi->block_state >= YAFFS_NUMBER_OF_BLOCK_STATES)
+		yaffs_trace(YAFFS_TRACE_VERIFY,
+			"Block %d has undefined state %d",
+			n, bi->block_state);
+
+	switch (bi->block_state) {
+	case YAFFS_BLOCK_STATE_UNKNOWN:
+	case YAFFS_BLOCK_STATE_SCANNING:
+	case YAFFS_BLOCK_STATE_NEEDS_SCAN:
+		yaffs_trace(YAFFS_TRACE_VERIFY,
+			"Block %d has bad run-state %s",
+			n, block_state_name[bi->block_state]);
+	}
+
+	/* Check pages in use and soft deletions are legal */
+
+	actually_used = bi->pages_in_use - bi->soft_del_pages;
+
+	if (bi->pages_in_use < 0 ||
+	    bi->pages_in_use > dev->param.chunks_per_block ||
+	    bi->soft_del_pages < 0 ||
+	    bi->soft_del_pages > dev->param.chunks_per_block ||
+	    actually_used < 0 || actually_used > dev->param.chunks_per_block)
+		yaffs_trace(YAFFS_TRACE_VERIFY,
+			"Block %d has illegal values pages_in_used %d soft_del_pages %d",
+			n, bi->pages_in_use, bi->soft_del_pages);
+
+	/* Check chunk bitmap legal */
+	in_use = yaffs_count_chunk_bits(dev, n);
+	if (in_use != bi->pages_in_use)
+		yaffs_trace(YAFFS_TRACE_VERIFY,
+			"Block %d has inconsistent values pages_in_use %d counted chunk bits %d",
+			n, bi->pages_in_use, in_use);
+}
+
+void yaffs_verify_collected_blk(struct yaffs_dev *dev,
+				struct yaffs_block_info *bi, int n)
+{
+	yaffs_verify_blk(dev, bi, n);
+
+	/* After collection the block should be in the erased state */
+
+	if (bi->block_state != YAFFS_BLOCK_STATE_COLLECTING &&
+	    bi->block_state != YAFFS_BLOCK_STATE_EMPTY) {
+		yaffs_trace(YAFFS_TRACE_ERROR,
+			"Block %d is in state %d after gc, should be erased",
+			n, bi->block_state);
+	}
+}
+
+void yaffs_verify_blocks(struct yaffs_dev *dev)
+{
+	int i;
+	int state_count[YAFFS_NUMBER_OF_BLOCK_STATES];
+	int illegal_states = 0;
+
+	if (yaffs_skip_verification(dev))
+		return;
+
+	memset(state_count, 0, sizeof(state_count));
+
+	for (i = dev->internal_start_block; i <= dev->internal_end_block; i++) {
+		struct yaffs_block_info *bi = yaffs_get_block_info(dev, i);
+		yaffs_verify_blk(dev, bi, i);
+
+		if (bi->block_state < YAFFS_NUMBER_OF_BLOCK_STATES)
+			state_count[bi->block_state]++;
+		else
+			illegal_states++;
+	}
+
+	yaffs_trace(YAFFS_TRACE_VERIFY,	"Block summary");
+
+	yaffs_trace(YAFFS_TRACE_VERIFY,
+		"%d blocks have illegal states",
+		illegal_states);
+	if (state_count[YAFFS_BLOCK_STATE_ALLOCATING] > 1)
+		yaffs_trace(YAFFS_TRACE_VERIFY,
+			"Too many allocating blocks");
+
+	for (i = 0; i < YAFFS_NUMBER_OF_BLOCK_STATES; i++)
+		yaffs_trace(YAFFS_TRACE_VERIFY,
+			"%s %d blocks",
+			block_state_name[i], state_count[i]);
+
+	if (dev->blocks_in_checkpt != state_count[YAFFS_BLOCK_STATE_CHECKPOINT])
+		yaffs_trace(YAFFS_TRACE_VERIFY,
+			"Checkpoint block count wrong dev %d count %d",
+			dev->blocks_in_checkpt,
+			state_count[YAFFS_BLOCK_STATE_CHECKPOINT]);
+
+	if (dev->n_erased_blocks != state_count[YAFFS_BLOCK_STATE_EMPTY])
+		yaffs_trace(YAFFS_TRACE_VERIFY,
+			"Erased block count wrong dev %d count %d",
+			dev->n_erased_blocks,
+			state_count[YAFFS_BLOCK_STATE_EMPTY]);
+
+	if (state_count[YAFFS_BLOCK_STATE_COLLECTING] > 1)
+		yaffs_trace(YAFFS_TRACE_VERIFY,
+			"Too many collecting blocks %d (max is 1)",
+			state_count[YAFFS_BLOCK_STATE_COLLECTING]);
+}
+
+/*
+ * Verify the object header. oh must be valid, but obj and tags may be NULL in
+ * which case those tests will not be performed.
+ */
+void yaffs_verify_oh(struct yaffs_obj *obj, struct yaffs_obj_hdr *oh,
+		     struct yaffs_ext_tags *tags, int parent_check)
+{
+	if (obj && yaffs_skip_verification(obj->my_dev))
+		return;
+
+	if (!(tags && obj && oh)) {
+		yaffs_trace(YAFFS_TRACE_VERIFY,
+			"Verifying object header tags %p obj %p oh %p",
+			tags, obj, oh);
+		return;
+	}
+
+	if (oh->type <= YAFFS_OBJECT_TYPE_UNKNOWN ||
+	    oh->type > YAFFS_OBJECT_TYPE_MAX)
+		yaffs_trace(YAFFS_TRACE_VERIFY,
+			"Obj %d header type is illegal value 0x%x",
+			tags->obj_id, oh->type);
+
+	if (tags->obj_id != obj->obj_id)
+		yaffs_trace(YAFFS_TRACE_VERIFY,
+			"Obj %d header mismatch obj_id %d",
+			tags->obj_id, obj->obj_id);
+
+	/*
+	 * Check that the object's parent ids match if parent_check requested.
+	 *
+	 * Tests do not apply to the root object.
+	 */
+
+	if (parent_check && tags->obj_id > 1 && !obj->parent)
+		yaffs_trace(YAFFS_TRACE_VERIFY,
+			"Obj %d header mismatch parent_id %d obj->parent is NULL",
+			tags->obj_id, oh->parent_obj_id);
+
+	if (parent_check && obj->parent &&
+	    oh->parent_obj_id != obj->parent->obj_id &&
+	    (oh->parent_obj_id != YAFFS_OBJECTID_UNLINKED ||
+	     obj->parent->obj_id != YAFFS_OBJECTID_DELETED))
+		yaffs_trace(YAFFS_TRACE_VERIFY,
+			"Obj %d header mismatch parent_id %d parent_obj_id %d",
+			tags->obj_id, oh->parent_obj_id,
+			obj->parent->obj_id);
+
+	if (tags->obj_id > 1 && oh->name[0] == 0)	/* Null name */
+		yaffs_trace(YAFFS_TRACE_VERIFY,
+			"Obj %d header name is NULL",
+			obj->obj_id);
+
+	if (tags->obj_id > 1 && ((u8) (oh->name[0])) == 0xff)	/* Junk name */
+		yaffs_trace(YAFFS_TRACE_VERIFY,
+			"Obj %d header name is 0xff",
+			obj->obj_id);
+}
+
+void yaffs_verify_file(struct yaffs_obj *obj)
+{
+	u32 x;
+	int required_depth;
+	int actual_depth;
+	int last_chunk;
+	u32 offset_in_chunk;
+	u32 the_chunk;
+
+	u32 i;
+	struct yaffs_dev *dev;
+	struct yaffs_ext_tags tags;
+	struct yaffs_tnode *tn;
+	u32 obj_id;
+
+	if (!obj)
+		return;
+
+	if (yaffs_skip_verification(obj->my_dev))
+		return;
+
+	dev = obj->my_dev;
+	obj_id = obj->obj_id;
+
+
+	/* Check file size is consistent with tnode depth */
+	yaffs_addr_to_chunk(dev, obj->variant.file_variant.file_size,
+				&last_chunk, &offset_in_chunk);
+	last_chunk++;
+	x = last_chunk >> YAFFS_TNODES_LEVEL0_BITS;
+	required_depth = 0;
+	while (x > 0) {
+		x >>= YAFFS_TNODES_INTERNAL_BITS;
+		required_depth++;
+	}
+
+	actual_depth = obj->variant.file_variant.top_level;
+
+	/* Check that the chunks in the tnode tree are all correct.
+	 * We do this by scanning through the tnode tree and
+	 * checking the tags for every chunk match.
+	 */
+
+	if (yaffs_skip_nand_verification(dev))
+		return;
+
+	for (i = 1; i <= last_chunk; i++) {
+		tn = yaffs_find_tnode_0(dev, &obj->variant.file_variant, i);
+
+		if (!tn)
+			continue;
+
+		the_chunk = yaffs_get_group_base(dev, tn, i);
+		if (the_chunk > 0) {
+			yaffs_rd_chunk_tags_nand(dev, the_chunk, NULL,
+						 &tags);
+			if (tags.obj_id != obj_id || tags.chunk_id != i)
+				yaffs_trace(YAFFS_TRACE_VERIFY,
+					"Object %d chunk_id %d NAND mismatch chunk %d tags (%d:%d)",
+					obj_id, i, the_chunk,
+					tags.obj_id, tags.chunk_id);
+		}
+	}
+}
+
+void yaffs_verify_link(struct yaffs_obj *obj)
+{
+	if (obj && yaffs_skip_verification(obj->my_dev))
+		return;
+
+	/* Verify sane equivalent object */
+}
+
+void yaffs_verify_symlink(struct yaffs_obj *obj)
+{
+	if (obj && yaffs_skip_verification(obj->my_dev))
+		return;
+
+	/* Verify symlink string */
+}
+
+void yaffs_verify_special(struct yaffs_obj *obj)
+{
+	if (obj && yaffs_skip_verification(obj->my_dev))
+		return;
+}
+
+void yaffs_verify_obj(struct yaffs_obj *obj)
+{
+	struct yaffs_dev *dev;
+	u32 chunk_min;
+	u32 chunk_max;
+	u32 chunk_id_ok;
+	u32 chunk_in_range;
+	u32 chunk_wrongly_deleted;
+	u32 chunk_valid;
+
+	if (!obj)
+		return;
+
+	if (obj->being_created)
+		return;
+
+	dev = obj->my_dev;
+
+	if (yaffs_skip_verification(dev))
+		return;
+
+	/* Check sane object header chunk */
+
+	chunk_min = dev->internal_start_block * dev->param.chunks_per_block;
+	chunk_max =
+	    (dev->internal_end_block + 1) * dev->param.chunks_per_block - 1;
+
+	chunk_in_range = (((unsigned)(obj->hdr_chunk)) >= chunk_min &&
+			  ((unsigned)(obj->hdr_chunk)) <= chunk_max);
+	chunk_id_ok = chunk_in_range || (obj->hdr_chunk == 0);
+	chunk_valid = chunk_in_range &&
+	    yaffs_check_chunk_bit(dev,
+				  obj->hdr_chunk / dev->param.chunks_per_block,
+				  obj->hdr_chunk % dev->param.chunks_per_block);
+	chunk_wrongly_deleted = chunk_in_range && !chunk_valid;
+
+	if (!obj->fake && (!chunk_id_ok || chunk_wrongly_deleted))
+		yaffs_trace(YAFFS_TRACE_VERIFY,
+			"Obj %d has chunk_id %d %s %s",
+			obj->obj_id, obj->hdr_chunk,
+			chunk_id_ok ? "" : ",out of range",
+			chunk_wrongly_deleted ? ",marked as deleted" : "");
+
+	if (chunk_valid && !yaffs_skip_nand_verification(dev)) {
+		struct yaffs_ext_tags tags;
+		struct yaffs_obj_hdr *oh;
+		u8 *buffer = yaffs_get_temp_buffer(dev);
+
+		oh = (struct yaffs_obj_hdr *)buffer;
+
+		yaffs_rd_chunk_tags_nand(dev, obj->hdr_chunk, buffer, &tags);
+
+		yaffs_verify_oh(obj, oh, &tags, 1);
+
+		yaffs_release_temp_buffer(dev, buffer);
+	}
+
+	/* Verify it has a parent */
+	if (obj && !obj->fake && (!obj->parent || obj->parent->my_dev != dev)) {
+		yaffs_trace(YAFFS_TRACE_VERIFY,
+			"Obj %d has parent pointer %p which does not look like an object",
+			obj->obj_id, obj->parent);
+	}
+
+	/* Verify parent is a directory */
+	if (obj->parent &&
+	    obj->parent->variant_type != YAFFS_OBJECT_TYPE_DIRECTORY) {
+		yaffs_trace(YAFFS_TRACE_VERIFY,
+			"Obj %d's parent is not a directory (type %d)",
+			obj->obj_id, obj->parent->variant_type);
+	}
+
+	switch (obj->variant_type) {
+	case YAFFS_OBJECT_TYPE_FILE:
+		yaffs_verify_file(obj);
+		break;
+	case YAFFS_OBJECT_TYPE_SYMLINK:
+		yaffs_verify_symlink(obj);
+		break;
+	case YAFFS_OBJECT_TYPE_DIRECTORY:
+		yaffs_verify_dir(obj);
+		break;
+	case YAFFS_OBJECT_TYPE_HARDLINK:
+		yaffs_verify_link(obj);
+		break;
+	case YAFFS_OBJECT_TYPE_SPECIAL:
+		yaffs_verify_special(obj);
+		break;
+	case YAFFS_OBJECT_TYPE_UNKNOWN:
+	default:
+		yaffs_trace(YAFFS_TRACE_VERIFY,
+			"Obj %d has illegaltype %d",
+		   obj->obj_id, obj->variant_type);
+		break;
+	}
+}
+
+void yaffs_verify_objects(struct yaffs_dev *dev)
+{
+	struct yaffs_obj *obj;
+	int i;
+	struct list_head *lh;
+
+	if (yaffs_skip_verification(dev))
+		return;
+
+	/* Iterate through the objects in each hash entry */
+
+	for (i = 0; i < YAFFS_NOBJECT_BUCKETS; i++) {
+		list_for_each(lh, &dev->obj_bucket[i].list) {
+			obj = list_entry(lh, struct yaffs_obj, hash_link);
+			yaffs_verify_obj(obj);
+		}
+	}
+}
+
+void yaffs_verify_obj_in_dir(struct yaffs_obj *obj)
+{
+	struct list_head *lh;
+	struct yaffs_obj *list_obj;
+	int count = 0;
+
+	if (!obj) {
+		yaffs_trace(YAFFS_TRACE_ALWAYS, "No object to verify");
+		BUG();
+		return;
+	}
+
+	if (yaffs_skip_verification(obj->my_dev))
+		return;
+
+	if (!obj->parent) {
+		yaffs_trace(YAFFS_TRACE_ALWAYS, "Object does not have parent");
+		BUG();
+		return;
+	}
+
+	if (obj->parent->variant_type != YAFFS_OBJECT_TYPE_DIRECTORY) {
+		yaffs_trace(YAFFS_TRACE_ALWAYS, "Parent is not directory");
+		BUG();
+	}
+
+	/* Iterate through the objects in each hash entry */
+
+	list_for_each(lh, &obj->parent->variant.dir_variant.children) {
+		list_obj = list_entry(lh, struct yaffs_obj, siblings);
+		yaffs_verify_obj(list_obj);
+		if (obj == list_obj)
+			count++;
+	}
+
+	if (count != 1) {
+		yaffs_trace(YAFFS_TRACE_ALWAYS,
+			"Object in directory %d times",
+			count);
+		BUG();
+	}
+}
+
+void yaffs_verify_dir(struct yaffs_obj *directory)
+{
+	struct list_head *lh;
+	struct yaffs_obj *list_obj;
+
+	if (!directory) {
+		BUG();
+		return;
+	}
+
+	if (yaffs_skip_full_verification(directory->my_dev))
+		return;
+
+	if (directory->variant_type != YAFFS_OBJECT_TYPE_DIRECTORY) {
+		yaffs_trace(YAFFS_TRACE_ALWAYS,
+			"Directory has wrong type: %d",
+			directory->variant_type);
+		BUG();
+	}
+
+	/* Iterate through the objects in each hash entry */
+
+	list_for_each(lh, &directory->variant.dir_variant.children) {
+		list_obj = list_entry(lh, struct yaffs_obj, siblings);
+		if (list_obj->parent != directory) {
+			yaffs_trace(YAFFS_TRACE_ALWAYS,
+				"Object in directory list has wrong parent %p",
+				list_obj->parent);
+			BUG();
+		}
+		yaffs_verify_obj_in_dir(list_obj);
+	}
+}
+
+static int yaffs_free_verification_failures;
+
+void yaffs_verify_free_chunks(struct yaffs_dev *dev)
+{
+	int counted;
+	int difference;
+
+	if (yaffs_skip_verification(dev))
+		return;
+
+	counted = yaffs_count_free_chunks(dev);
+
+	difference = dev->n_free_chunks - counted;
+
+	if (difference) {
+		yaffs_trace(YAFFS_TRACE_ALWAYS,
+			"Freechunks verification failure %d %d %d",
+			dev->n_free_chunks, counted, difference);
+		yaffs_free_verification_failures++;
+	}
+}
+
+int yaffs_verify_file_sane(struct yaffs_obj *in)
+{
+	(void) in;
+	return YAFFS_OK;
+}
diff --git a/linux-bsp/asm-study/yaffs2/yaffs2/yaffs_verify.h b/linux-bsp/asm-study/yaffs2/yaffs2/yaffs_verify.h
new file mode 100644
index 0000000..4f4af8d
--- /dev/null
+++ b/linux-bsp/asm-study/yaffs2/yaffs2/yaffs_verify.h
@@ -0,0 +1,43 @@
+/*
+ * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
+ *
+ * Copyright (C) 2002-2011 Aleph One Ltd.
+ *   for Toby Churchill Ltd and Brightstar Engineering
+ *
+ * Created by Charles Manning <charles@aleph1.co.uk>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 2.1 as
+ * published by the Free Software Foundation.
+ *
+ * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
+ */
+
+#ifndef __YAFFS_VERIFY_H__
+#define __YAFFS_VERIFY_H__
+
+#include "yaffs_guts.h"
+
+void yaffs_verify_blk(struct yaffs_dev *dev, struct yaffs_block_info *bi,
+		      int n);
+void yaffs_verify_collected_blk(struct yaffs_dev *dev,
+				struct yaffs_block_info *bi, int n);
+void yaffs_verify_blocks(struct yaffs_dev *dev);
+
+void yaffs_verify_oh(struct yaffs_obj *obj, struct yaffs_obj_hdr *oh,
+		     struct yaffs_ext_tags *tags, int parent_check);
+void yaffs_verify_file(struct yaffs_obj *obj);
+void yaffs_verify_link(struct yaffs_obj *obj);
+void yaffs_verify_symlink(struct yaffs_obj *obj);
+void yaffs_verify_special(struct yaffs_obj *obj);
+void yaffs_verify_obj(struct yaffs_obj *obj);
+void yaffs_verify_objects(struct yaffs_dev *dev);
+void yaffs_verify_obj_in_dir(struct yaffs_obj *obj);
+void yaffs_verify_dir(struct yaffs_obj *directory);
+void yaffs_verify_free_chunks(struct yaffs_dev *dev);
+
+int yaffs_verify_file_sane(struct yaffs_obj *obj);
+
+int yaffs_skip_verification(struct yaffs_dev *dev);
+
+#endif
diff --git a/linux-bsp/asm-study/yaffs2/yaffs2/yaffs_yaffs1.c b/linux-bsp/asm-study/yaffs2/yaffs2/yaffs_yaffs1.c
new file mode 100644
index 0000000..d277e20
--- /dev/null
+++ b/linux-bsp/asm-study/yaffs2/yaffs2/yaffs_yaffs1.c
@@ -0,0 +1,422 @@
+/*
+ * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
+ *
+ * Copyright (C) 2002-2011 Aleph One Ltd.
+ *   for Toby Churchill Ltd and Brightstar Engineering
+ *
+ * Created by Charles Manning <charles@aleph1.co.uk>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include "yaffs_yaffs1.h"
+#include "yportenv.h"
+#include "yaffs_trace.h"
+#include "yaffs_bitmap.h"
+#include "yaffs_getblockinfo.h"
+#include "yaffs_nand.h"
+#include "yaffs_attribs.h"
+
+int yaffs1_scan(struct yaffs_dev *dev)
+{
+	struct yaffs_ext_tags tags;
+	int blk;
+	int result;
+	int chunk;
+	int c;
+	int deleted;
+	enum yaffs_block_state state;
+	LIST_HEAD(hard_list);
+	struct yaffs_block_info *bi;
+	u32 seq_number;
+	struct yaffs_obj_hdr *oh;
+	struct yaffs_obj *in;
+	struct yaffs_obj *parent;
+	int alloc_failed = 0;
+	struct yaffs_shadow_fixer *shadow_fixers = NULL;
+	u8 *chunk_data;
+
+	yaffs_trace(YAFFS_TRACE_SCAN,
+		"yaffs1_scan starts  intstartblk %d intendblk %d...",
+		dev->internal_start_block, dev->internal_end_block);
+
+	chunk_data = yaffs_get_temp_buffer(dev);
+
+	dev->seq_number = YAFFS_LOWEST_SEQUENCE_NUMBER;
+
+	/* Scan all the blocks to determine their state */
+	bi = dev->block_info;
+	for (blk = dev->internal_start_block; blk <= dev->internal_end_block;
+	     blk++) {
+		yaffs_clear_chunk_bits(dev, blk);
+		bi->pages_in_use = 0;
+		bi->soft_del_pages = 0;
+
+		yaffs_query_init_block_state(dev, blk, &state, &seq_number);
+
+		bi->block_state = state;
+		bi->seq_number = seq_number;
+
+		if (bi->seq_number == YAFFS_SEQUENCE_BAD_BLOCK)
+			bi->block_state = state = YAFFS_BLOCK_STATE_DEAD;
+
+		yaffs_trace(YAFFS_TRACE_SCAN_DEBUG,
+			"Block scanning block %d state %d seq %d",
+			blk, state, seq_number);
+
+		if (state == YAFFS_BLOCK_STATE_DEAD) {
+			yaffs_trace(YAFFS_TRACE_BAD_BLOCKS,
+				"block %d is bad", blk);
+		} else if (state == YAFFS_BLOCK_STATE_EMPTY) {
+			yaffs_trace(YAFFS_TRACE_SCAN_DEBUG, "Block empty ");
+			dev->n_erased_blocks++;
+			dev->n_free_chunks += dev->param.chunks_per_block;
+		}
+		bi++;
+	}
+
+	/* For each block.... */
+	for (blk = dev->internal_start_block;
+	     !alloc_failed && blk <= dev->internal_end_block; blk++) {
+
+		cond_resched();
+
+		bi = yaffs_get_block_info(dev, blk);
+		state = bi->block_state;
+
+		deleted = 0;
+
+		/* For each chunk in each block that needs scanning.... */
+		for (c = 0;
+			!alloc_failed && c < dev->param.chunks_per_block &&
+			state == YAFFS_BLOCK_STATE_NEEDS_SCAN; c++) {
+			/* Read the tags and decide what to do */
+			chunk = blk * dev->param.chunks_per_block + c;
+
+			result = yaffs_rd_chunk_tags_nand(dev, chunk, NULL,
+							  &tags);
+
+			/* Let's have a good look at this chunk... */
+
+			if (tags.ecc_result == YAFFS_ECC_RESULT_UNFIXED ||
+			    tags.is_deleted) {
+				/* YAFFS1 only...
+				 * A deleted chunk
+				 */
+				deleted++;
+				dev->n_free_chunks++;
+			} else if (!tags.chunk_used) {
+				/* An unassigned chunk in the block
+				 * This means that either the block is empty or
+				 * this is the one being allocated from
+				 */
+
+				if (c == 0) {
+					/* We're looking at the first chunk in
+					 *the block so the block is unused */
+					state = YAFFS_BLOCK_STATE_EMPTY;
+					dev->n_erased_blocks++;
+				} else {
+					/* this is the block being allocated */
+					yaffs_trace(YAFFS_TRACE_SCAN,
+						" Allocating from %d %d",
+						blk, c);
+					state = YAFFS_BLOCK_STATE_ALLOCATING;
+					dev->alloc_block = blk;
+					dev->alloc_page = c;
+					dev->alloc_block_finder = blk;
+
+				}
+
+				dev->n_free_chunks +=
+				    (dev->param.chunks_per_block - c);
+			} else if (tags.chunk_id > 0) {
+				/* chunk_id > 0 so it is a data chunk... */
+				unsigned int endpos;
+
+				yaffs_set_chunk_bit(dev, blk, c);
+				bi->pages_in_use++;
+
+				in = yaffs_find_or_create_by_number(dev,
+							tags.obj_id,
+							YAFFS_OBJECT_TYPE_FILE);
+				/* PutChunkIntoFile checks for a clash
+				 * (two data chunks with the same chunk_id).
+				 */
+
+				if (!in)
+					alloc_failed = 1;
+
+				if (in) {
+					if (!yaffs_put_chunk_in_file
+					    (in, tags.chunk_id, chunk, 1))
+						alloc_failed = 1;
+				}
+
+				endpos =
+				    (tags.chunk_id - 1) *
+				    dev->data_bytes_per_chunk +
+				    tags.n_bytes;
+				if (in &&
+				    in->variant_type ==
+				     YAFFS_OBJECT_TYPE_FILE &&
+				    in->variant.file_variant.scanned_size <
+				      endpos) {
+					in->variant.file_variant.scanned_size =
+					    endpos;
+					if (!dev->param.use_header_file_size) {
+						in->variant.
+						    file_variant.file_size =
+						    in->variant.
+						    file_variant.scanned_size;
+					}
+
+				}
+			} else {
+				/* chunk_id == 0, so it is an ObjectHeader.
+				 * Make the object
+				 */
+				yaffs_set_chunk_bit(dev, blk, c);
+				bi->pages_in_use++;
+
+				result = yaffs_rd_chunk_tags_nand(dev, chunk,
+								  chunk_data,
+								  NULL);
+
+				oh = (struct yaffs_obj_hdr *)chunk_data;
+
+				in = yaffs_find_by_number(dev, tags.obj_id);
+				if (in && in->variant_type != oh->type) {
+					/* This should not happen, but somehow
+					 * Wev'e ended up with an obj_id that
+					 * has been reused but not yet deleted,
+					 * and worse still it has changed type.
+					 * Delete the old object.
+					 */
+
+					yaffs_del_obj(in);
+					in = NULL;
+				}
+
+				in = yaffs_find_or_create_by_number(dev,
+								tags.obj_id,
+								oh->type);
+
+				if (!in)
+					alloc_failed = 1;
+
+				if (in && oh->shadows_obj > 0) {
+
+					struct yaffs_shadow_fixer *fixer;
+					fixer =
+						kmalloc(sizeof
+						(struct yaffs_shadow_fixer),
+						GFP_NOFS);
+					if (fixer) {
+						fixer->next = shadow_fixers;
+						shadow_fixers = fixer;
+						fixer->obj_id = tags.obj_id;
+						fixer->shadowed_id =
+						    oh->shadows_obj;
+						yaffs_trace(YAFFS_TRACE_SCAN,
+							" Shadow fixer: %d shadows %d",
+							fixer->obj_id,
+							fixer->shadowed_id);
+
+					}
+
+				}
+
+				if (in && in->valid) {
+					/* We have already filled this one.
+					 * We have a duplicate and need to
+					 * resolve it. */
+
+					unsigned existing_serial = in->serial;
+					unsigned new_serial =
+					    tags.serial_number;
+
+					if (((existing_serial + 1) & 3) ==
+					    new_serial) {
+						/* Use new one - destroy the
+						 * exisiting one */
+						yaffs_chunk_del(dev,
+								in->hdr_chunk,
+								1, __LINE__);
+						in->valid = 0;
+					} else {
+						/* Use existing - destroy
+						 * this one. */
+						yaffs_chunk_del(dev, chunk, 1,
+								__LINE__);
+					}
+				}
+
+				if (in && !in->valid &&
+				    (tags.obj_id == YAFFS_OBJECTID_ROOT ||
+				     tags.obj_id ==
+				     YAFFS_OBJECTID_LOSTNFOUND)) {
+					/* We only load some info, don't fiddle
+					 * with directory structure */
+					in->valid = 1;
+					in->variant_type = oh->type;
+
+					in->yst_mode = oh->yst_mode;
+					yaffs_load_attribs(in, oh);
+					in->hdr_chunk = chunk;
+					in->serial = tags.serial_number;
+
+				} else if (in && !in->valid) {
+					/* we need to load this info */
+
+					in->valid = 1;
+					in->variant_type = oh->type;
+
+					in->yst_mode = oh->yst_mode;
+					yaffs_load_attribs(in, oh);
+					in->hdr_chunk = chunk;
+					in->serial = tags.serial_number;
+
+					yaffs_set_obj_name_from_oh(in, oh);
+					in->dirty = 0;
+
+					/* directory stuff...
+					 * hook up to parent
+					 */
+
+					parent =
+					    yaffs_find_or_create_by_number
+					    (dev, oh->parent_obj_id,
+					     YAFFS_OBJECT_TYPE_DIRECTORY);
+					if (!parent)
+						alloc_failed = 1;
+					if (parent && parent->variant_type ==
+					    YAFFS_OBJECT_TYPE_UNKNOWN) {
+						/* Set up as a directory */
+						parent->variant_type =
+						    YAFFS_OBJECT_TYPE_DIRECTORY;
+						INIT_LIST_HEAD(&parent->
+							variant.dir_variant.
+							children);
+					} else if (!parent ||
+						parent->variant_type !=
+						YAFFS_OBJECT_TYPE_DIRECTORY) {
+						/* Hoosterman, a problem....
+						 * We're trying to use a
+						 * non-directory as a directory
+						 */
+
+						yaffs_trace(YAFFS_TRACE_ERROR,
+							"yaffs tragedy: attempting to use non-directory as a directory in scan. Put in lost+found."
+							);
+						parent = dev->lost_n_found;
+					}
+
+					yaffs_add_obj_to_dir(parent, in);
+
+					switch (in->variant_type) {
+					case YAFFS_OBJECT_TYPE_UNKNOWN:
+						/* Todo got a problem */
+						break;
+					case YAFFS_OBJECT_TYPE_FILE:
+						if (dev->param.
+						    use_header_file_size)
+							in->variant.
+							file_variant.file_size
+							= yaffs_oh_to_size(oh);
+						break;
+					case YAFFS_OBJECT_TYPE_HARDLINK:
+						in->variant.
+						    hardlink_variant.equiv_id =
+						    oh->equiv_id;
+						list_add(&in->hard_links,
+								&hard_list);
+						break;
+					case YAFFS_OBJECT_TYPE_DIRECTORY:
+						/* Do nothing */
+						break;
+					case YAFFS_OBJECT_TYPE_SPECIAL:
+						/* Do nothing */
+						break;
+					case YAFFS_OBJECT_TYPE_SYMLINK:
+						in->variant.symlink_variant.
+						    alias =
+						    yaffs_clone_str(oh->alias);
+						if (!in->variant.
+						    symlink_variant.alias)
+							alloc_failed = 1;
+						break;
+					}
+				}
+			}
+		}
+
+		if (state == YAFFS_BLOCK_STATE_NEEDS_SCAN) {
+			/* If we got this far while scanning,
+			 * then the block is fully allocated. */
+			state = YAFFS_BLOCK_STATE_FULL;
+		}
+
+		if (state == YAFFS_BLOCK_STATE_ALLOCATING) {
+			/* If the block was partially allocated then
+			 * treat it as fully allocated. */
+			state = YAFFS_BLOCK_STATE_FULL;
+			dev->alloc_block = -1;
+		}
+
+		bi->block_state = state;
+
+		/* Now let's see if it was dirty */
+		if (bi->pages_in_use == 0 &&
+		    !bi->has_shrink_hdr &&
+		    bi->block_state == YAFFS_BLOCK_STATE_FULL)
+			yaffs_block_became_dirty(dev, blk);
+	}
+
+	/* Ok, we've done all the scanning.
+	 * Fix up the hard link chains.
+	 * We should now have scanned all the objects, now it's time to add
+	 * these hardlinks.
+	 */
+
+	yaffs_link_fixup(dev, &hard_list);
+
+	/*
+	 * Fix up any shadowed objects.
+	 * There should not be more than one of these.
+	 */
+	{
+		struct yaffs_shadow_fixer *fixer;
+		struct yaffs_obj *obj;
+
+		while (shadow_fixers) {
+			fixer = shadow_fixers;
+			shadow_fixers = fixer->next;
+			/* Complete the rename transaction by deleting the
+			 * shadowed object then setting the object header
+			 to unshadowed.
+			 */
+			obj = yaffs_find_by_number(dev, fixer->shadowed_id);
+			if (obj)
+				yaffs_del_obj(obj);
+
+			obj = yaffs_find_by_number(dev, fixer->obj_id);
+
+			if (obj)
+				yaffs_update_oh(obj, NULL, 1, 0, 0, NULL);
+
+			kfree(fixer);
+		}
+	}
+
+	yaffs_release_temp_buffer(dev, chunk_data);
+
+	if (alloc_failed)
+		return YAFFS_FAIL;
+
+	yaffs_trace(YAFFS_TRACE_SCAN, "yaffs1_scan ends");
+
+	return YAFFS_OK;
+}
diff --git a/linux-bsp/asm-study/yaffs2/yaffs2/yaffs_yaffs1.h b/linux-bsp/asm-study/yaffs2/yaffs2/yaffs_yaffs1.h
new file mode 100644
index 0000000..97e2fdd
--- /dev/null
+++ b/linux-bsp/asm-study/yaffs2/yaffs2/yaffs_yaffs1.h
@@ -0,0 +1,22 @@
+/*
+ * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
+ *
+ * Copyright (C) 2002-2011 Aleph One Ltd.
+ *   for Toby Churchill Ltd and Brightstar Engineering
+ *
+ * Created by Charles Manning <charles@aleph1.co.uk>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 2.1 as
+ * published by the Free Software Foundation.
+ *
+ * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
+ */
+
+#ifndef __YAFFS_YAFFS1_H__
+#define __YAFFS_YAFFS1_H__
+
+#include "yaffs_guts.h"
+int yaffs1_scan(struct yaffs_dev *dev);
+
+#endif
diff --git a/linux-bsp/asm-study/yaffs2/yaffs2/yaffs_yaffs2.c b/linux-bsp/asm-study/yaffs2/yaffs2/yaffs_yaffs2.c
new file mode 100644
index 0000000..f1dc972
--- /dev/null
+++ b/linux-bsp/asm-study/yaffs2/yaffs2/yaffs_yaffs2.c
@@ -0,0 +1,1532 @@
+/*
+ * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
+ *
+ * Copyright (C) 2002-2011 Aleph One Ltd.
+ *   for Toby Churchill Ltd and Brightstar Engineering
+ *
+ * Created by Charles Manning <charles@aleph1.co.uk>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include "yaffs_guts.h"
+#include "yaffs_trace.h"
+#include "yaffs_yaffs2.h"
+#include "yaffs_checkptrw.h"
+#include "yaffs_bitmap.h"
+#include "yaffs_nand.h"
+#include "yaffs_getblockinfo.h"
+#include "yaffs_verify.h"
+#include "yaffs_attribs.h"
+#include "yaffs_summary.h"
+
+/*
+ * Checkpoints are really no benefit on very small partitions.
+ *
+ * To save space on small partitions don't bother with checkpoints unless
+ * the partition is at least this big.
+ */
+#define YAFFS_CHECKPOINT_MIN_BLOCKS 60
+#define YAFFS_SMALL_HOLE_THRESHOLD 4
+
+/*
+ * Oldest Dirty Sequence Number handling.
+ */
+
+/* yaffs_calc_oldest_dirty_seq()
+ * yaffs2_find_oldest_dirty_seq()
+ * Calculate the oldest dirty sequence number if we don't know it.
+ */
+void yaffs_calc_oldest_dirty_seq(struct yaffs_dev *dev)
+{
+	int i;
+	unsigned seq;
+	unsigned block_no = 0;
+	struct yaffs_block_info *b;
+
+	if (!dev->param.is_yaffs2)
+		return;
+
+	/* Find the oldest dirty sequence number. */
+	seq = dev->seq_number + 1;
+	b = dev->block_info;
+	for (i = dev->internal_start_block; i <= dev->internal_end_block; i++) {
+		if (b->block_state == YAFFS_BLOCK_STATE_FULL &&
+		    (b->pages_in_use - b->soft_del_pages) <
+		    dev->param.chunks_per_block &&
+		    b->seq_number < seq) {
+			seq = b->seq_number;
+			block_no = i;
+		}
+		b++;
+	}
+
+	if (block_no) {
+		dev->oldest_dirty_seq = seq;
+		dev->oldest_dirty_block = block_no;
+	}
+}
+
+void yaffs2_find_oldest_dirty_seq(struct yaffs_dev *dev)
+{
+	if (!dev->param.is_yaffs2)
+		return;
+
+	if (!dev->oldest_dirty_seq)
+		yaffs_calc_oldest_dirty_seq(dev);
+}
+
+/*
+ * yaffs_clear_oldest_dirty_seq()
+ * Called when a block is erased or marked bad. (ie. when its seq_number
+ * becomes invalid). If the value matches the oldest then we clear
+ * dev->oldest_dirty_seq to force its recomputation.
+ */
+void yaffs2_clear_oldest_dirty_seq(struct yaffs_dev *dev,
+				   struct yaffs_block_info *bi)
+{
+
+	if (!dev->param.is_yaffs2)
+		return;
+
+	if (!bi || bi->seq_number == dev->oldest_dirty_seq) {
+		dev->oldest_dirty_seq = 0;
+		dev->oldest_dirty_block = 0;
+	}
+}
+
+/*
+ * yaffs2_update_oldest_dirty_seq()
+ * Update the oldest dirty sequence number whenever we dirty a block.
+ * Only do this if the oldest_dirty_seq is actually being tracked.
+ */
+void yaffs2_update_oldest_dirty_seq(struct yaffs_dev *dev, unsigned block_no,
+				    struct yaffs_block_info *bi)
+{
+	if (!dev->param.is_yaffs2)
+		return;
+
+	if (dev->oldest_dirty_seq) {
+		if (dev->oldest_dirty_seq > bi->seq_number) {
+			dev->oldest_dirty_seq = bi->seq_number;
+			dev->oldest_dirty_block = block_no;
+		}
+	}
+}
+
+int yaffs_block_ok_for_gc(struct yaffs_dev *dev, struct yaffs_block_info *bi)
+{
+
+	if (!dev->param.is_yaffs2)
+		return 1;	/* disqualification only applies to yaffs2. */
+
+	if (!bi->has_shrink_hdr)
+		return 1;	/* can gc */
+
+	yaffs2_find_oldest_dirty_seq(dev);
+
+	/* Can't do gc of this block if there are any blocks older than this
+	 * one that have discarded pages.
+	 */
+	return (bi->seq_number <= dev->oldest_dirty_seq);
+}
+
+/*
+ * yaffs2_find_refresh_block()
+ * periodically finds the oldest full block by sequence number for refreshing.
+ * Only for yaffs2.
+ */
+u32 yaffs2_find_refresh_block(struct yaffs_dev *dev)
+{
+	u32 b;
+	u32 oldest = 0;
+	u32 oldest_seq = 0;
+	struct yaffs_block_info *bi;
+
+	if (!dev->param.is_yaffs2)
+		return oldest;
+
+	/*
+	 * If refresh period < 10 then refreshing is disabled.
+	 */
+	if (dev->param.refresh_period < 10)
+		return oldest;
+
+	/*
+	 * Fix broken values.
+	 */
+	if (dev->refresh_skip > dev->param.refresh_period)
+		dev->refresh_skip = dev->param.refresh_period;
+
+	if (dev->refresh_skip > 0)
+		return oldest;
+
+	/*
+	 * Refresh skip is now zero.
+	 * We'll do a refresh this time around....
+	 * Update the refresh skip and find the oldest block.
+	 */
+	dev->refresh_skip = dev->param.refresh_period;
+	dev->refresh_count++;
+	bi = dev->block_info;
+	for (b = dev->internal_start_block; b <= dev->internal_end_block; b++) {
+
+		if (bi->block_state == YAFFS_BLOCK_STATE_FULL) {
+
+			if (oldest < 1 || bi->seq_number < oldest_seq) {
+				oldest = b;
+				oldest_seq = bi->seq_number;
+			}
+		}
+		bi++;
+	}
+
+	if (oldest > 0) {
+		yaffs_trace(YAFFS_TRACE_GC,
+			"GC refresh count %d selected block %d with seq_number %d",
+			dev->refresh_count, oldest, oldest_seq);
+	}
+
+	return oldest;
+}
+
+int yaffs2_checkpt_required(struct yaffs_dev *dev)
+{
+	int nblocks;
+
+	if (!dev->param.is_yaffs2)
+		return 0;
+
+	nblocks = dev->internal_end_block - dev->internal_start_block + 1;
+
+	return !dev->param.skip_checkpt_wr &&
+	    !dev->read_only && (nblocks >= YAFFS_CHECKPOINT_MIN_BLOCKS);
+}
+
+int yaffs_calc_checkpt_blocks_required(struct yaffs_dev *dev)
+{
+	int retval;
+	int n_bytes = 0;
+	int n_blocks;
+	int dev_blocks;
+
+	if (!dev->param.is_yaffs2)
+		return 0;
+
+	if (!dev->checkpoint_blocks_required && yaffs2_checkpt_required(dev)) {
+		/* Not a valid value so recalculate */
+		dev_blocks = dev->param.end_block - dev->param.start_block + 1;
+		n_bytes += sizeof(struct yaffs_checkpt_validity);
+		n_bytes += sizeof(struct yaffs_checkpt_dev);
+		n_bytes += dev_blocks * sizeof(struct yaffs_block_info);
+		n_bytes += dev_blocks * dev->chunk_bit_stride;
+		n_bytes +=
+		    (sizeof(struct yaffs_checkpt_obj) + sizeof(u32)) *
+		    dev->n_obj;
+		n_bytes += (dev->tnode_size + sizeof(u32)) * dev->n_tnodes;
+		n_bytes += sizeof(struct yaffs_checkpt_validity);
+		n_bytes += sizeof(u32);	/* checksum */
+
+		/* Round up and add 2 blocks to allow for some bad blocks,
+		 * so add 3 */
+
+		n_blocks =
+		    (n_bytes /
+		     (dev->data_bytes_per_chunk *
+		      dev->param.chunks_per_block)) + 3;
+
+		dev->checkpoint_blocks_required = n_blocks;
+	}
+
+	retval = dev->checkpoint_blocks_required - dev->blocks_in_checkpt;
+	if (retval < 0)
+		retval = 0;
+	return retval;
+}
+
+/*--------------------- Checkpointing --------------------*/
+
+static int yaffs2_wr_checkpt_validity_marker(struct yaffs_dev *dev, int head)
+{
+	struct yaffs_checkpt_validity cp;
+
+	memset(&cp, 0, sizeof(cp));
+
+	cp.struct_type = sizeof(cp);
+	cp.magic = YAFFS_MAGIC;
+	cp.version = YAFFS_CHECKPOINT_VERSION;
+	cp.head = (head) ? 1 : 0;
+
+	return (yaffs2_checkpt_wr(dev, &cp, sizeof(cp)) == sizeof(cp)) ? 1 : 0;
+}
+
+static int yaffs2_rd_checkpt_validity_marker(struct yaffs_dev *dev, int head)
+{
+	struct yaffs_checkpt_validity cp;
+	int ok;
+
+	ok = (yaffs2_checkpt_rd(dev, &cp, sizeof(cp)) == sizeof(cp));
+
+	if (ok)
+		ok = (cp.struct_type == sizeof(cp)) &&
+		    (cp.magic == YAFFS_MAGIC) &&
+		    (cp.version == YAFFS_CHECKPOINT_VERSION) &&
+		    (cp.head == ((head) ? 1 : 0));
+	return ok ? 1 : 0;
+}
+
+static void yaffs2_dev_to_checkpt_dev(struct yaffs_checkpt_dev *cp,
+				      struct yaffs_dev *dev)
+{
+	cp->n_erased_blocks = dev->n_erased_blocks;
+	cp->alloc_block = dev->alloc_block;
+	cp->alloc_page = dev->alloc_page;
+	cp->n_free_chunks = dev->n_free_chunks;
+
+	cp->n_deleted_files = dev->n_deleted_files;
+	cp->n_unlinked_files = dev->n_unlinked_files;
+	cp->n_bg_deletions = dev->n_bg_deletions;
+	cp->seq_number = dev->seq_number;
+
+}
+
+static void yaffs_checkpt_dev_to_dev(struct yaffs_dev *dev,
+				     struct yaffs_checkpt_dev *cp)
+{
+	dev->n_erased_blocks = cp->n_erased_blocks;
+	dev->alloc_block = cp->alloc_block;
+	dev->alloc_page = cp->alloc_page;
+	dev->n_free_chunks = cp->n_free_chunks;
+
+	dev->n_deleted_files = cp->n_deleted_files;
+	dev->n_unlinked_files = cp->n_unlinked_files;
+	dev->n_bg_deletions = cp->n_bg_deletions;
+	dev->seq_number = cp->seq_number;
+}
+
+static int yaffs2_wr_checkpt_dev(struct yaffs_dev *dev)
+{
+	struct yaffs_checkpt_dev cp;
+	u32 n_bytes;
+	u32 n_blocks = dev->internal_end_block - dev->internal_start_block + 1;
+	int ok;
+
+	/* Write device runtime values */
+	yaffs2_dev_to_checkpt_dev(&cp, dev);
+	cp.struct_type = sizeof(cp);
+
+	ok = (yaffs2_checkpt_wr(dev, &cp, sizeof(cp)) == sizeof(cp));
+	if (!ok)
+		return 0;
+
+	/* Write block info */
+	n_bytes = n_blocks * sizeof(struct yaffs_block_info);
+	ok = (yaffs2_checkpt_wr(dev, dev->block_info, n_bytes) == n_bytes);
+	if (!ok)
+		return 0;
+
+	/* Write chunk bits */
+	n_bytes = n_blocks * dev->chunk_bit_stride;
+	ok = (yaffs2_checkpt_wr(dev, dev->chunk_bits, n_bytes) == n_bytes);
+
+	return ok ? 1 : 0;
+}
+
+static int yaffs2_rd_checkpt_dev(struct yaffs_dev *dev)
+{
+	struct yaffs_checkpt_dev cp;
+	u32 n_bytes;
+	u32 n_blocks =
+	    (dev->internal_end_block - dev->internal_start_block + 1);
+	int ok;
+
+	ok = (yaffs2_checkpt_rd(dev, &cp, sizeof(cp)) == sizeof(cp));
+	if (!ok)
+		return 0;
+
+	if (cp.struct_type != sizeof(cp))
+		return 0;
+
+	yaffs_checkpt_dev_to_dev(dev, &cp);
+
+	n_bytes = n_blocks * sizeof(struct yaffs_block_info);
+
+	ok = (yaffs2_checkpt_rd(dev, dev->block_info, n_bytes) == n_bytes);
+
+	if (!ok)
+		return 0;
+
+	n_bytes = n_blocks * dev->chunk_bit_stride;
+
+	ok = (yaffs2_checkpt_rd(dev, dev->chunk_bits, n_bytes) == n_bytes);
+
+	return ok ? 1 : 0;
+}
+
+static void yaffs2_obj_checkpt_obj(struct yaffs_checkpt_obj *cp,
+				   struct yaffs_obj *obj)
+{
+	cp->obj_id = obj->obj_id;
+	cp->parent_id = (obj->parent) ? obj->parent->obj_id : 0;
+	cp->hdr_chunk = obj->hdr_chunk;
+	cp->variant_type = obj->variant_type;
+	cp->deleted = obj->deleted;
+	cp->soft_del = obj->soft_del;
+	cp->unlinked = obj->unlinked;
+	cp->fake = obj->fake;
+	cp->rename_allowed = obj->rename_allowed;
+	cp->unlink_allowed = obj->unlink_allowed;
+	cp->serial = obj->serial;
+	cp->n_data_chunks = obj->n_data_chunks;
+
+	if (obj->variant_type == YAFFS_OBJECT_TYPE_FILE)
+		cp->size_or_equiv_obj = obj->variant.file_variant.file_size;
+	else if (obj->variant_type == YAFFS_OBJECT_TYPE_HARDLINK)
+		cp->size_or_equiv_obj = obj->variant.hardlink_variant.equiv_id;
+}
+
+static int yaffs2_checkpt_obj_to_obj(struct yaffs_obj *obj,
+				     struct yaffs_checkpt_obj *cp)
+{
+	struct yaffs_obj *parent;
+
+	if (obj->variant_type != cp->variant_type) {
+		yaffs_trace(YAFFS_TRACE_ERROR,
+			"Checkpoint read object %d type %d chunk %d does not match existing object type %d",
+			cp->obj_id, cp->variant_type, cp->hdr_chunk,
+			obj->variant_type);
+		return 0;
+	}
+
+	obj->obj_id = cp->obj_id;
+
+	if (cp->parent_id)
+		parent = yaffs_find_or_create_by_number(obj->my_dev,
+						cp->parent_id,
+						YAFFS_OBJECT_TYPE_DIRECTORY);
+	else
+		parent = NULL;
+
+	if (parent) {
+		if (parent->variant_type != YAFFS_OBJECT_TYPE_DIRECTORY) {
+			yaffs_trace(YAFFS_TRACE_ALWAYS,
+				"Checkpoint read object %d parent %d type %d chunk %d Parent type, %d, not directory",
+				cp->obj_id, cp->parent_id,
+				cp->variant_type, cp->hdr_chunk,
+				parent->variant_type);
+			return 0;
+		}
+		yaffs_add_obj_to_dir(parent, obj);
+	}
+
+	obj->hdr_chunk = cp->hdr_chunk;
+	obj->variant_type = cp->variant_type;
+	obj->deleted = cp->deleted;
+	obj->soft_del = cp->soft_del;
+	obj->unlinked = cp->unlinked;
+	obj->fake = cp->fake;
+	obj->rename_allowed = cp->rename_allowed;
+	obj->unlink_allowed = cp->unlink_allowed;
+	obj->serial = cp->serial;
+	obj->n_data_chunks = cp->n_data_chunks;
+
+	if (obj->variant_type == YAFFS_OBJECT_TYPE_FILE)
+		obj->variant.file_variant.file_size = cp->size_or_equiv_obj;
+	else if (obj->variant_type == YAFFS_OBJECT_TYPE_HARDLINK)
+		obj->variant.hardlink_variant.equiv_id = cp->size_or_equiv_obj;
+
+	if (obj->hdr_chunk > 0)
+		obj->lazy_loaded = 1;
+	return 1;
+}
+
+static int yaffs2_checkpt_tnode_worker(struct yaffs_obj *in,
+				       struct yaffs_tnode *tn, u32 level,
+				       int chunk_offset)
+{
+	int i;
+	struct yaffs_dev *dev = in->my_dev;
+	int ok = 1;
+	u32 base_offset;
+
+	if (!tn)
+		return 1;
+
+	if (level > 0) {
+		for (i = 0; i < YAFFS_NTNODES_INTERNAL && ok; i++) {
+			if (!tn->internal[i])
+				continue;
+			ok = yaffs2_checkpt_tnode_worker(in,
+				 tn->internal[i],
+				 level - 1,
+				 (chunk_offset <<
+				  YAFFS_TNODES_INTERNAL_BITS) + i);
+		}
+		return ok;
+	}
+
+	/* Level 0 tnode */
+	base_offset = chunk_offset << YAFFS_TNODES_LEVEL0_BITS;
+	ok = (yaffs2_checkpt_wr(dev, &base_offset, sizeof(base_offset)) ==
+			sizeof(base_offset));
+	if (ok)
+		ok = (yaffs2_checkpt_wr(dev, tn, dev->tnode_size) ==
+			dev->tnode_size);
+
+	return ok;
+}
+
+static int yaffs2_wr_checkpt_tnodes(struct yaffs_obj *obj)
+{
+	u32 end_marker = ~0;
+	int ok = 1;
+
+	if (obj->variant_type != YAFFS_OBJECT_TYPE_FILE)
+		return ok;
+
+	ok = yaffs2_checkpt_tnode_worker(obj,
+					 obj->variant.file_variant.top,
+					 obj->variant.file_variant.
+					 top_level, 0);
+	if (ok)
+		ok = (yaffs2_checkpt_wr(obj->my_dev, &end_marker,
+				sizeof(end_marker)) == sizeof(end_marker));
+
+	return ok ? 1 : 0;
+}
+
+static int yaffs2_rd_checkpt_tnodes(struct yaffs_obj *obj)
+{
+	u32 base_chunk;
+	int ok = 1;
+	struct yaffs_dev *dev = obj->my_dev;
+	struct yaffs_file_var *file_stuct_ptr = &obj->variant.file_variant;
+	struct yaffs_tnode *tn;
+	int nread = 0;
+
+	ok = (yaffs2_checkpt_rd(dev, &base_chunk, sizeof(base_chunk)) ==
+	      sizeof(base_chunk));
+
+	while (ok && (~base_chunk)) {
+		nread++;
+		/* Read level 0 tnode */
+
+		tn = yaffs_get_tnode(dev);
+		if (tn)
+			ok = (yaffs2_checkpt_rd(dev, tn, dev->tnode_size) ==
+				dev->tnode_size);
+		else
+			ok = 0;
+
+		if (tn && ok)
+			ok = yaffs_add_find_tnode_0(dev,
+						    file_stuct_ptr,
+						    base_chunk, tn) ? 1 : 0;
+
+		if (ok)
+			ok = (yaffs2_checkpt_rd
+			      (dev, &base_chunk,
+			       sizeof(base_chunk)) == sizeof(base_chunk));
+	}
+
+	yaffs_trace(YAFFS_TRACE_CHECKPOINT,
+		"Checkpoint read tnodes %d records, last %d. ok %d",
+		nread, base_chunk, ok);
+
+	return ok ? 1 : 0;
+}
+
+static int yaffs2_wr_checkpt_objs(struct yaffs_dev *dev)
+{
+	struct yaffs_obj *obj;
+	struct yaffs_checkpt_obj cp;
+	int i;
+	int ok = 1;
+	struct list_head *lh;
+
+	/* Iterate through the objects in each hash entry,
+	 * dumping them to the checkpointing stream.
+	 */
+
+	for (i = 0; ok && i < YAFFS_NOBJECT_BUCKETS; i++) {
+		list_for_each(lh, &dev->obj_bucket[i].list) {
+			obj = list_entry(lh, struct yaffs_obj, hash_link);
+			if (!obj->defered_free) {
+				yaffs2_obj_checkpt_obj(&cp, obj);
+				cp.struct_type = sizeof(cp);
+
+				yaffs_trace(YAFFS_TRACE_CHECKPOINT,
+					"Checkpoint write object %d parent %d type %d chunk %d obj addr %p",
+					cp.obj_id, cp.parent_id,
+					cp.variant_type, cp.hdr_chunk, obj);
+
+				ok = (yaffs2_checkpt_wr(dev, &cp,
+						sizeof(cp)) == sizeof(cp));
+
+				if (ok &&
+					obj->variant_type ==
+					YAFFS_OBJECT_TYPE_FILE)
+					ok = yaffs2_wr_checkpt_tnodes(obj);
+			}
+		}
+	}
+
+	/* Dump end of list */
+	memset(&cp, 0xff, sizeof(struct yaffs_checkpt_obj));
+	cp.struct_type = sizeof(cp);
+
+	if (ok)
+		ok = (yaffs2_checkpt_wr(dev, &cp, sizeof(cp)) == sizeof(cp));
+
+	return ok ? 1 : 0;
+}
+
+static int yaffs2_rd_checkpt_objs(struct yaffs_dev *dev)
+{
+	struct yaffs_obj *obj;
+	struct yaffs_checkpt_obj cp;
+	int ok = 1;
+	int done = 0;
+	LIST_HEAD(hard_list);
+
+
+	while (ok && !done) {
+		ok = (yaffs2_checkpt_rd(dev, &cp, sizeof(cp)) == sizeof(cp));
+		if (cp.struct_type != sizeof(cp)) {
+			yaffs_trace(YAFFS_TRACE_CHECKPOINT,
+				"struct size %d instead of %d ok %d",
+				cp.struct_type, (int)sizeof(cp), ok);
+			ok = 0;
+		}
+
+		yaffs_trace(YAFFS_TRACE_CHECKPOINT,
+			"Checkpoint read object %d parent %d type %d chunk %d ",
+			cp.obj_id, cp.parent_id, cp.variant_type,
+			cp.hdr_chunk);
+
+		if (ok && cp.obj_id == ~0) {
+			done = 1;
+		} else if (ok) {
+			obj =
+			    yaffs_find_or_create_by_number(dev, cp.obj_id,
+							   cp.variant_type);
+			if (obj) {
+				ok = yaffs2_checkpt_obj_to_obj(obj, &cp);
+				if (!ok)
+					break;
+				if (obj->variant_type ==
+					YAFFS_OBJECT_TYPE_FILE) {
+					ok = yaffs2_rd_checkpt_tnodes(obj);
+				} else if (obj->variant_type ==
+					YAFFS_OBJECT_TYPE_HARDLINK) {
+					list_add(&obj->hard_links, &hard_list);
+				}
+			} else {
+				ok = 0;
+			}
+		}
+	}
+
+	if (ok)
+		yaffs_link_fixup(dev, &hard_list);
+
+	return ok ? 1 : 0;
+}
+
+static int yaffs2_wr_checkpt_sum(struct yaffs_dev *dev)
+{
+	u32 checkpt_sum;
+	int ok;
+
+	yaffs2_get_checkpt_sum(dev, &checkpt_sum);
+
+	ok = (yaffs2_checkpt_wr(dev, &checkpt_sum, sizeof(checkpt_sum)) ==
+		sizeof(checkpt_sum));
+
+	if (!ok)
+		return 0;
+
+	return 1;
+}
+
+static int yaffs2_rd_checkpt_sum(struct yaffs_dev *dev)
+{
+	u32 checkpt_sum0;
+	u32 checkpt_sum1;
+	int ok;
+
+	yaffs2_get_checkpt_sum(dev, &checkpt_sum0);
+
+	ok = (yaffs2_checkpt_rd(dev, &checkpt_sum1, sizeof(checkpt_sum1)) ==
+		sizeof(checkpt_sum1));
+
+	if (!ok)
+		return 0;
+
+	if (checkpt_sum0 != checkpt_sum1)
+		return 0;
+
+	return 1;
+}
+
+static int yaffs2_wr_checkpt_data(struct yaffs_dev *dev)
+{
+	int ok = 1;
+
+	if (!yaffs2_checkpt_required(dev)) {
+		yaffs_trace(YAFFS_TRACE_CHECKPOINT,
+			"skipping checkpoint write");
+		ok = 0;
+	}
+
+	if (ok)
+		ok = yaffs2_checkpt_open(dev, 1);
+
+	if (ok) {
+		yaffs_trace(YAFFS_TRACE_CHECKPOINT,
+			"write checkpoint validity");
+		ok = yaffs2_wr_checkpt_validity_marker(dev, 1);
+	}
+	if (ok) {
+		yaffs_trace(YAFFS_TRACE_CHECKPOINT,
+			"write checkpoint device");
+		ok = yaffs2_wr_checkpt_dev(dev);
+	}
+	if (ok) {
+		yaffs_trace(YAFFS_TRACE_CHECKPOINT,
+			"write checkpoint objects");
+		ok = yaffs2_wr_checkpt_objs(dev);
+	}
+	if (ok) {
+		yaffs_trace(YAFFS_TRACE_CHECKPOINT,
+			"write checkpoint validity");
+		ok = yaffs2_wr_checkpt_validity_marker(dev, 0);
+	}
+
+	if (ok)
+		ok = yaffs2_wr_checkpt_sum(dev);
+
+	if (!yaffs_checkpt_close(dev))
+		ok = 0;
+
+	if (ok)
+		dev->is_checkpointed = 1;
+	else
+		dev->is_checkpointed = 0;
+
+	return dev->is_checkpointed;
+}
+
+static int yaffs2_rd_checkpt_data(struct yaffs_dev *dev)
+{
+	int ok = 1;
+
+	if (!dev->param.is_yaffs2)
+		ok = 0;
+
+	if (ok && dev->param.skip_checkpt_rd) {
+		yaffs_trace(YAFFS_TRACE_CHECKPOINT,
+			"skipping checkpoint read");
+		ok = 0;
+	}
+
+	if (ok)
+		ok = yaffs2_checkpt_open(dev, 0); /* open for read */
+
+	if (ok) {
+		yaffs_trace(YAFFS_TRACE_CHECKPOINT,
+			"read checkpoint validity");
+		ok = yaffs2_rd_checkpt_validity_marker(dev, 1);
+	}
+	if (ok) {
+		yaffs_trace(YAFFS_TRACE_CHECKPOINT,
+			"read checkpoint device");
+		ok = yaffs2_rd_checkpt_dev(dev);
+	}
+	if (ok) {
+		yaffs_trace(YAFFS_TRACE_CHECKPOINT,
+			"read checkpoint objects");
+		ok = yaffs2_rd_checkpt_objs(dev);
+	}
+	if (ok) {
+		yaffs_trace(YAFFS_TRACE_CHECKPOINT,
+			"read checkpoint validity");
+		ok = yaffs2_rd_checkpt_validity_marker(dev, 0);
+	}
+
+	if (ok) {
+		ok = yaffs2_rd_checkpt_sum(dev);
+		yaffs_trace(YAFFS_TRACE_CHECKPOINT,
+			"read checkpoint checksum %d", ok);
+	}
+
+	if (!yaffs_checkpt_close(dev))
+		ok = 0;
+
+	if (ok)
+		dev->is_checkpointed = 1;
+	else
+		dev->is_checkpointed = 0;
+
+	return ok ? 1 : 0;
+}
+
+void yaffs2_checkpt_invalidate(struct yaffs_dev *dev)
+{
+	if (dev->is_checkpointed || dev->blocks_in_checkpt > 0) {
+		dev->is_checkpointed = 0;
+		yaffs2_checkpt_invalidate_stream(dev);
+	}
+	if (dev->param.sb_dirty_fn)
+		dev->param.sb_dirty_fn(dev);
+}
+
+int yaffs_checkpoint_save(struct yaffs_dev *dev)
+{
+	yaffs_trace(YAFFS_TRACE_CHECKPOINT,
+		"save entry: is_checkpointed %d",
+		dev->is_checkpointed);
+
+	yaffs_verify_objects(dev);
+	yaffs_verify_blocks(dev);
+	yaffs_verify_free_chunks(dev);
+
+	if (!dev->is_checkpointed) {
+		yaffs2_checkpt_invalidate(dev);
+		yaffs2_wr_checkpt_data(dev);
+	}
+
+	yaffs_trace(YAFFS_TRACE_CHECKPOINT | YAFFS_TRACE_MOUNT,
+		"save exit: is_checkpointed %d",
+		dev->is_checkpointed);
+
+	return dev->is_checkpointed;
+}
+
+int yaffs2_checkpt_restore(struct yaffs_dev *dev)
+{
+	int retval;
+
+	yaffs_trace(YAFFS_TRACE_CHECKPOINT,
+		"restore entry: is_checkpointed %d",
+		dev->is_checkpointed);
+
+	retval = yaffs2_rd_checkpt_data(dev);
+
+	if (dev->is_checkpointed) {
+		yaffs_verify_objects(dev);
+		yaffs_verify_blocks(dev);
+		yaffs_verify_free_chunks(dev);
+	}
+
+	yaffs_trace(YAFFS_TRACE_CHECKPOINT,
+		"restore exit: is_checkpointed %d",
+		dev->is_checkpointed);
+
+	return retval;
+}
+
+int yaffs2_handle_hole(struct yaffs_obj *obj, loff_t new_size)
+{
+	/* if new_size > old_file_size.
+	 * We're going to be writing a hole.
+	 * If the hole is small then write zeros otherwise write a start
+	 * of hole marker.
+	 */
+	loff_t old_file_size;
+	loff_t increase;
+	int small_hole;
+	int result = YAFFS_OK;
+	struct yaffs_dev *dev = NULL;
+	u8 *local_buffer = NULL;
+	int small_increase_ok = 0;
+
+	if (!obj)
+		return YAFFS_FAIL;
+
+	if (obj->variant_type != YAFFS_OBJECT_TYPE_FILE)
+		return YAFFS_FAIL;
+
+	dev = obj->my_dev;
+
+	/* Bail out if not yaffs2 mode */
+	if (!dev->param.is_yaffs2)
+		return YAFFS_OK;
+
+	old_file_size = obj->variant.file_variant.file_size;
+
+	if (new_size <= old_file_size)
+		return YAFFS_OK;
+
+	increase = new_size - old_file_size;
+
+	if (increase < YAFFS_SMALL_HOLE_THRESHOLD * dev->data_bytes_per_chunk &&
+	    yaffs_check_alloc_available(dev, YAFFS_SMALL_HOLE_THRESHOLD + 1))
+		small_hole = 1;
+	else
+		small_hole = 0;
+
+	if (small_hole)
+		local_buffer = yaffs_get_temp_buffer(dev);
+
+	if (local_buffer) {
+		/* fill hole with zero bytes */
+		loff_t pos = old_file_size;
+		int this_write;
+		int written;
+		memset(local_buffer, 0, dev->data_bytes_per_chunk);
+		small_increase_ok = 1;
+
+		while (increase > 0 && small_increase_ok) {
+			this_write = increase;
+			if (this_write > dev->data_bytes_per_chunk)
+				this_write = dev->data_bytes_per_chunk;
+			written =
+			    yaffs_do_file_wr(obj, local_buffer, pos, this_write,
+					     0);
+			if (written == this_write) {
+				pos += this_write;
+				increase -= this_write;
+			} else {
+				small_increase_ok = 0;
+			}
+		}
+
+		yaffs_release_temp_buffer(dev, local_buffer);
+
+		/* If out of space then reverse any chunks we've added */
+		if (!small_increase_ok)
+			yaffs_resize_file_down(obj, old_file_size);
+	}
+
+	if (!small_increase_ok &&
+	    obj->parent &&
+	    obj->parent->obj_id != YAFFS_OBJECTID_UNLINKED &&
+	    obj->parent->obj_id != YAFFS_OBJECTID_DELETED) {
+		/* Write a hole start header with the old file size */
+		yaffs_update_oh(obj, NULL, 0, 1, 0, NULL);
+	}
+
+	return result;
+}
+
+struct yaffs_block_index {
+	int seq;
+	int block;
+};
+
+static int yaffs2_ybicmp(const void *a, const void *b)
+{
+	int aseq = ((struct yaffs_block_index *)a)->seq;
+	int bseq = ((struct yaffs_block_index *)b)->seq;
+	int ablock = ((struct yaffs_block_index *)a)->block;
+	int bblock = ((struct yaffs_block_index *)b)->block;
+
+	if (aseq == bseq)
+		return ablock - bblock;
+
+	return aseq - bseq;
+}
+
+static inline int yaffs2_scan_chunk(struct yaffs_dev *dev,
+		struct yaffs_block_info *bi,
+		int blk, int chunk_in_block,
+		int *found_chunks,
+		u8 *chunk_data,
+		struct list_head *hard_list,
+		int summary_available)
+{
+	struct yaffs_obj_hdr *oh;
+	struct yaffs_obj *in;
+	struct yaffs_obj *parent;
+	int equiv_id;
+	loff_t file_size;
+	int is_shrink;
+	int is_unlinked;
+	struct yaffs_ext_tags tags;
+	int result;
+	int alloc_failed = 0;
+	int chunk = blk * dev->param.chunks_per_block + chunk_in_block;
+	struct yaffs_file_var *file_var;
+	struct yaffs_hardlink_var *hl_var;
+	struct yaffs_symlink_var *sl_var;
+
+	if (summary_available) {
+		result = yaffs_summary_fetch(dev, &tags, chunk_in_block);
+		tags.seq_number = bi->seq_number;
+	}
+
+	if (!summary_available || tags.obj_id == 0) {
+		result = yaffs_rd_chunk_tags_nand(dev, chunk, NULL, &tags);
+		dev->tags_used++;
+	} else {
+		dev->summary_used++;
+	}
+
+	/* Let's have a good look at this chunk... */
+
+	if (!tags.chunk_used) {
+		/* An unassigned chunk in the block.
+		 * If there are used chunks after this one, then
+		 * it is a chunk that was skipped due to failing
+		 * the erased check. Just skip it so that it can
+		 * be deleted.
+		 * But, more typically, We get here when this is
+		 * an unallocated chunk and his means that
+		 * either the block is empty or this is the one
+		 * being allocated from
+		 */
+
+		if (*found_chunks) {
+			/* This is a chunk that was skipped due
+			 * to failing the erased check */
+		} else if (chunk_in_block == 0) {
+			/* We're looking at the first chunk in
+			 * the block so the block is unused */
+			bi->block_state = YAFFS_BLOCK_STATE_EMPTY;
+			dev->n_erased_blocks++;
+		} else {
+			if (bi->block_state == YAFFS_BLOCK_STATE_NEEDS_SCAN ||
+			    bi->block_state == YAFFS_BLOCK_STATE_ALLOCATING) {
+				if (dev->seq_number == bi->seq_number) {
+					/* Allocating from this block*/
+					yaffs_trace(YAFFS_TRACE_SCAN,
+					    " Allocating from %d %d",
+					    blk, chunk_in_block);
+
+					bi->block_state =
+						YAFFS_BLOCK_STATE_ALLOCATING;
+					dev->alloc_block = blk;
+					dev->alloc_page = chunk_in_block;
+					dev->alloc_block_finder = blk;
+				} else {
+					/* This is a partially written block
+					 * that is not the current
+					 * allocation block.
+					 */
+					yaffs_trace(YAFFS_TRACE_SCAN,
+						"Partially written block %d detected. gc will fix this.",
+						blk);
+				}
+			}
+		}
+
+		dev->n_free_chunks++;
+
+	} else if (tags.ecc_result ==
+		YAFFS_ECC_RESULT_UNFIXED) {
+		yaffs_trace(YAFFS_TRACE_SCAN,
+			" Unfixed ECC in chunk(%d:%d), chunk ignored",
+			blk, chunk_in_block);
+			dev->n_free_chunks++;
+	} else if (tags.obj_id > YAFFS_MAX_OBJECT_ID ||
+		   tags.chunk_id > YAFFS_MAX_CHUNK_ID ||
+		   tags.obj_id == YAFFS_OBJECTID_SUMMARY ||
+		   (tags.chunk_id > 0 &&
+		     tags.n_bytes > dev->data_bytes_per_chunk) ||
+		   tags.seq_number != bi->seq_number) {
+		yaffs_trace(YAFFS_TRACE_SCAN,
+			"Chunk (%d:%d) with bad tags:obj = %d, chunk_id = %d, n_bytes = %d, ignored",
+			blk, chunk_in_block, tags.obj_id,
+			tags.chunk_id, tags.n_bytes);
+		dev->n_free_chunks++;
+	} else if (tags.chunk_id > 0) {
+		/* chunk_id > 0 so it is a data chunk... */
+		loff_t endpos;
+		loff_t chunk_base = (tags.chunk_id - 1) *
+					dev->data_bytes_per_chunk;
+
+		*found_chunks = 1;
+
+		yaffs_set_chunk_bit(dev, blk, chunk_in_block);
+		bi->pages_in_use++;
+
+		in = yaffs_find_or_create_by_number(dev,
+					tags.obj_id,
+					YAFFS_OBJECT_TYPE_FILE);
+		if (!in)
+			/* Out of memory */
+			alloc_failed = 1;
+
+		if (in &&
+		    in->variant_type == YAFFS_OBJECT_TYPE_FILE &&
+		    chunk_base < in->variant.file_variant.shrink_size) {
+			/* This has not been invalidated by
+			 * a resize */
+			if (!yaffs_put_chunk_in_file(in, tags.chunk_id,
+								chunk, -1))
+				alloc_failed = 1;
+
+			/* File size is calculated by looking at
+			 * the data chunks if we have not
+			 * seen an object header yet.
+			 * Stop this practice once we find an
+			 * object header.
+			 */
+			endpos = chunk_base + tags.n_bytes;
+
+			if (!in->valid &&
+			    in->variant.file_variant.scanned_size < endpos) {
+				in->variant.file_variant.
+				    scanned_size = endpos;
+				in->variant.file_variant.
+				    file_size = endpos;
+			}
+		} else if (in) {
+			/* This chunk has been invalidated by a
+			 * resize, or a past file deletion
+			 * so delete the chunk*/
+			yaffs_chunk_del(dev, chunk, 1, __LINE__);
+		}
+	} else {
+		/* chunk_id == 0, so it is an ObjectHeader.
+		 * Thus, we read in the object header and make
+		 * the object
+		 */
+		*found_chunks = 1;
+
+		yaffs_set_chunk_bit(dev, blk, chunk_in_block);
+		bi->pages_in_use++;
+
+		oh = NULL;
+		in = NULL;
+
+		if (tags.extra_available) {
+			in = yaffs_find_or_create_by_number(dev,
+					tags.obj_id,
+					tags.extra_obj_type);
+			if (!in)
+				alloc_failed = 1;
+		}
+
+		if (!in ||
+		    (!in->valid && dev->param.disable_lazy_load) ||
+		    tags.extra_shadows ||
+		    (!in->valid && (tags.obj_id == YAFFS_OBJECTID_ROOT ||
+				 tags.obj_id == YAFFS_OBJECTID_LOSTNFOUND))) {
+
+			/* If we don't have  valid info then we
+			 * need to read the chunk
+			 * TODO In future we can probably defer
+			 * reading the chunk and living with
+			 * invalid data until needed.
+			 */
+
+			result = yaffs_rd_chunk_tags_nand(dev,
+						  chunk,
+						  chunk_data,
+						  NULL);
+
+			oh = (struct yaffs_obj_hdr *)chunk_data;
+
+			if (dev->param.inband_tags) {
+				/* Fix up the header if they got
+				 * corrupted by inband tags */
+				oh->shadows_obj =
+				    oh->inband_shadowed_obj_id;
+				oh->is_shrink =
+				    oh->inband_is_shrink;
+			}
+
+			if (!in) {
+				in = yaffs_find_or_create_by_number(dev,
+							tags.obj_id, oh->type);
+				if (!in)
+					alloc_failed = 1;
+			}
+		}
+
+		if (!in) {
+			/* TODO Hoosterman we have a problem! */
+			yaffs_trace(YAFFS_TRACE_ERROR,
+				"yaffs tragedy: Could not make object for object  %d at chunk %d during scan",
+				tags.obj_id, chunk);
+			return YAFFS_FAIL;
+		}
+
+		if (in->valid) {
+			/* We have already filled this one.
+			 * We have a duplicate that will be
+			 * discarded, but we first have to suck
+			 * out resize info if it is a file.
+			 */
+			if ((in->variant_type == YAFFS_OBJECT_TYPE_FILE) &&
+				((oh && oh->type == YAFFS_OBJECT_TYPE_FILE) ||
+				 (tags.extra_available &&
+				  tags.extra_obj_type == YAFFS_OBJECT_TYPE_FILE)
+				)) {
+				loff_t this_size = (oh) ?
+					yaffs_oh_to_size(oh) :
+					tags.extra_file_size;
+				u32 parent_obj_id = (oh) ?
+					oh->parent_obj_id :
+					tags.extra_parent_id;
+
+				is_shrink = (oh) ?
+					oh->is_shrink :
+					tags.extra_is_shrink;
+
+				/* If it is deleted (unlinked
+				 * at start also means deleted)
+				 * we treat the file size as
+				 * being zeroed at this point.
+				 */
+				if (parent_obj_id == YAFFS_OBJECTID_DELETED ||
+				    parent_obj_id == YAFFS_OBJECTID_UNLINKED) {
+					this_size = 0;
+					is_shrink = 1;
+				}
+
+				if (is_shrink &&
+				    in->variant.file_variant.shrink_size >
+				    this_size)
+					in->variant.file_variant.shrink_size =
+					this_size;
+
+				if (is_shrink)
+					bi->has_shrink_hdr = 1;
+			}
+			/* Use existing - destroy this one. */
+			yaffs_chunk_del(dev, chunk, 1, __LINE__);
+		}
+
+		if (!in->valid && in->variant_type !=
+		    (oh ? oh->type : tags.extra_obj_type))
+			yaffs_trace(YAFFS_TRACE_ERROR,
+				"yaffs tragedy: Bad object type, %d != %d, for object %d at chunk %d during scan",
+				oh ? oh->type : tags.extra_obj_type,
+				in->variant_type, tags.obj_id,
+				chunk);
+
+		if (!in->valid &&
+		    (tags.obj_id == YAFFS_OBJECTID_ROOT ||
+		     tags.obj_id == YAFFS_OBJECTID_LOSTNFOUND)) {
+			/* We only load some info, don't fiddle
+			 * with directory structure */
+			in->valid = 1;
+
+			if (oh) {
+				in->yst_mode = oh->yst_mode;
+				yaffs_load_attribs(in, oh);
+				in->lazy_loaded = 0;
+			} else {
+				in->lazy_loaded = 1;
+			}
+			in->hdr_chunk = chunk;
+
+		} else if (!in->valid) {
+			/* we need to load this info */
+			in->valid = 1;
+			in->hdr_chunk = chunk;
+			if (oh) {
+				in->variant_type = oh->type;
+				in->yst_mode = oh->yst_mode;
+				yaffs_load_attribs(in, oh);
+
+				if (oh->shadows_obj > 0)
+					yaffs_handle_shadowed_obj(dev,
+					     oh->shadows_obj, 1);
+
+				yaffs_set_obj_name_from_oh(in, oh);
+				parent = yaffs_find_or_create_by_number(dev,
+						oh->parent_obj_id,
+						YAFFS_OBJECT_TYPE_DIRECTORY);
+				file_size = yaffs_oh_to_size(oh);
+				is_shrink = oh->is_shrink;
+				equiv_id = oh->equiv_id;
+			} else {
+				in->variant_type = tags.extra_obj_type;
+				parent = yaffs_find_or_create_by_number(dev,
+						tags.extra_parent_id,
+						YAFFS_OBJECT_TYPE_DIRECTORY);
+				file_size = tags.extra_file_size;
+				is_shrink = tags.extra_is_shrink;
+				equiv_id = tags.extra_equiv_id;
+				in->lazy_loaded = 1;
+			}
+			in->dirty = 0;
+
+			if (!parent)
+				alloc_failed = 1;
+
+			/* directory stuff...
+			 * hook up to parent
+			 */
+
+			if (parent &&
+			    parent->variant_type == YAFFS_OBJECT_TYPE_UNKNOWN) {
+				/* Set up as a directory */
+				parent->variant_type =
+					YAFFS_OBJECT_TYPE_DIRECTORY;
+				INIT_LIST_HEAD(&parent->
+						variant.dir_variant.children);
+			} else if (!parent ||
+				   parent->variant_type !=
+					YAFFS_OBJECT_TYPE_DIRECTORY) {
+				/* Hoosterman, another problem....
+				 * Trying to use a non-directory as a directory
+				 */
+
+				yaffs_trace(YAFFS_TRACE_ERROR,
+					"yaffs tragedy: attempting to use non-directory as a directory in scan. Put in lost+found."
+					);
+				parent = dev->lost_n_found;
+			}
+			yaffs_add_obj_to_dir(parent, in);
+
+			is_unlinked = (parent == dev->del_dir) ||
+					(parent == dev->unlinked_dir);
+
+			if (is_shrink)
+				/* Mark the block */
+				bi->has_shrink_hdr = 1;
+
+			/* Note re hardlinks.
+			 * Since we might scan a hardlink before its equivalent
+			 * object is scanned we put them all in a list.
+			 * After scanning is complete, we should have all the
+			 * objects, so we run through this list and fix up all
+			 * the chains.
+			 */
+
+			switch (in->variant_type) {
+			case YAFFS_OBJECT_TYPE_UNKNOWN:
+				/* Todo got a problem */
+				break;
+			case YAFFS_OBJECT_TYPE_FILE:
+				file_var = &in->variant.file_variant;
+				if (file_var->scanned_size < file_size) {
+					/* This covers the case where the file
+					 * size is greater than the data held.
+					 * This will happen if the file is
+					 * resized to be larger than its
+					 * current data extents.
+					 */
+					file_var->file_size = file_size;
+					file_var->scanned_size = file_size;
+				}
+
+				if (file_var->shrink_size > file_size)
+					file_var->shrink_size = file_size;
+
+				break;
+			case YAFFS_OBJECT_TYPE_HARDLINK:
+				hl_var = &in->variant.hardlink_variant;
+				if (!is_unlinked) {
+					hl_var->equiv_id = equiv_id;
+					list_add(&in->hard_links, hard_list);
+				}
+				break;
+			case YAFFS_OBJECT_TYPE_DIRECTORY:
+				/* Do nothing */
+				break;
+			case YAFFS_OBJECT_TYPE_SPECIAL:
+				/* Do nothing */
+				break;
+			case YAFFS_OBJECT_TYPE_SYMLINK:
+				sl_var = &in->variant.symlink_variant;
+				if (oh) {
+					sl_var->alias =
+					    yaffs_clone_str(oh->alias);
+					if (!sl_var->alias)
+						alloc_failed = 1;
+				}
+				break;
+			}
+		}
+	}
+	return alloc_failed ? YAFFS_FAIL : YAFFS_OK;
+}
+
+int yaffs2_scan_backwards(struct yaffs_dev *dev)
+{
+	int blk;
+	int block_iter;
+	int start_iter;
+	int end_iter;
+	int n_to_scan = 0;
+	enum yaffs_block_state state;
+	int c;
+	int deleted;
+	LIST_HEAD(hard_list);
+	struct yaffs_block_info *bi;
+	u32 seq_number;
+	int n_blocks = dev->internal_end_block - dev->internal_start_block + 1;
+	u8 *chunk_data;
+	int found_chunks;
+	int alloc_failed = 0;
+	struct yaffs_block_index *block_index = NULL;
+	int alt_block_index = 0;
+	int summary_available;
+
+	yaffs_trace(YAFFS_TRACE_SCAN,
+		"yaffs2_scan_backwards starts  intstartblk %d intendblk %d...",
+		dev->internal_start_block, dev->internal_end_block);
+
+	dev->seq_number = YAFFS_LOWEST_SEQUENCE_NUMBER;
+
+	block_index =
+		kmalloc(n_blocks * sizeof(struct yaffs_block_index), GFP_NOFS);
+
+	if (!block_index) {
+		block_index =
+		    vmalloc(n_blocks * sizeof(struct yaffs_block_index));
+		alt_block_index = 1;
+	}
+
+	if (!block_index) {
+		yaffs_trace(YAFFS_TRACE_SCAN,
+			"yaffs2_scan_backwards() could not allocate block index!"
+			);
+		return YAFFS_FAIL;
+	}
+
+	dev->blocks_in_checkpt = 0;
+
+	chunk_data = yaffs_get_temp_buffer(dev);
+
+	/* Scan all the blocks to determine their state */
+	bi = dev->block_info;
+	for (blk = dev->internal_start_block; blk <= dev->internal_end_block;
+	     blk++) {
+		yaffs_clear_chunk_bits(dev, blk);
+		bi->pages_in_use = 0;
+		bi->soft_del_pages = 0;
+
+		yaffs_query_init_block_state(dev, blk, &state, &seq_number);
+
+		bi->block_state = state;
+		bi->seq_number = seq_number;
+
+		if (bi->seq_number == YAFFS_SEQUENCE_CHECKPOINT_DATA)
+			bi->block_state = YAFFS_BLOCK_STATE_CHECKPOINT;
+		if (bi->seq_number == YAFFS_SEQUENCE_BAD_BLOCK)
+			bi->block_state = YAFFS_BLOCK_STATE_DEAD;
+
+		yaffs_trace(YAFFS_TRACE_SCAN_DEBUG,
+			"Block scanning block %d state %d seq %d",
+			blk, bi->block_state, seq_number);
+
+		if (bi->block_state == YAFFS_BLOCK_STATE_CHECKPOINT) {
+			dev->blocks_in_checkpt++;
+
+		} else if (bi->block_state == YAFFS_BLOCK_STATE_DEAD) {
+			yaffs_trace(YAFFS_TRACE_BAD_BLOCKS,
+				"block %d is bad", blk);
+		} else if (bi->block_state == YAFFS_BLOCK_STATE_EMPTY) {
+			yaffs_trace(YAFFS_TRACE_SCAN_DEBUG, "Block empty ");
+			dev->n_erased_blocks++;
+			dev->n_free_chunks += dev->param.chunks_per_block;
+		} else if (bi->block_state ==
+				YAFFS_BLOCK_STATE_NEEDS_SCAN) {
+			/* Determine the highest sequence number */
+			if (seq_number >= YAFFS_LOWEST_SEQUENCE_NUMBER &&
+			    seq_number < YAFFS_HIGHEST_SEQUENCE_NUMBER) {
+				block_index[n_to_scan].seq = seq_number;
+				block_index[n_to_scan].block = blk;
+				n_to_scan++;
+				if (seq_number >= dev->seq_number)
+					dev->seq_number = seq_number;
+			} else {
+				/* TODO: Nasty sequence number! */
+				yaffs_trace(YAFFS_TRACE_SCAN,
+					"Block scanning block %d has bad sequence number %d",
+					blk, seq_number);
+			}
+		}
+		bi++;
+	}
+
+	yaffs_trace(YAFFS_TRACE_SCAN, "%d blocks to be sorted...", n_to_scan);
+
+	cond_resched();
+
+	/* Sort the blocks by sequence number */
+	sort(block_index, n_to_scan, sizeof(struct yaffs_block_index),
+		   yaffs2_ybicmp, NULL);
+
+	cond_resched();
+
+	yaffs_trace(YAFFS_TRACE_SCAN, "...done");
+
+	/* Now scan the blocks looking at the data. */
+	start_iter = 0;
+	end_iter = n_to_scan - 1;
+	yaffs_trace(YAFFS_TRACE_SCAN_DEBUG, "%d blocks to scan", n_to_scan);
+
+	/* For each block.... backwards */
+	for (block_iter = end_iter;
+	     !alloc_failed && block_iter >= start_iter;
+	     block_iter--) {
+		/* Cooperative multitasking! This loop can run for so
+		   long that watchdog timers expire. */
+		cond_resched();
+
+		/* get the block to scan in the correct order */
+		blk = block_index[block_iter].block;
+		bi = yaffs_get_block_info(dev, blk);
+		deleted = 0;
+
+		summary_available = yaffs_summary_read(dev, dev->sum_tags, blk);
+
+		/* For each chunk in each block that needs scanning.... */
+		found_chunks = 0;
+		if (summary_available)
+			c = dev->chunks_per_summary - 1;
+		else
+			c = dev->param.chunks_per_block - 1;
+
+		for (/* c is already initialised */;
+		     !alloc_failed && c >= 0 &&
+		     (bi->block_state == YAFFS_BLOCK_STATE_NEEDS_SCAN ||
+		      bi->block_state == YAFFS_BLOCK_STATE_ALLOCATING);
+		      c--) {
+			/* Scan backwards...
+			 * Read the tags and decide what to do
+			 */
+			if (yaffs2_scan_chunk(dev, bi, blk, c,
+					&found_chunks, chunk_data,
+					&hard_list, summary_available) ==
+					YAFFS_FAIL)
+				alloc_failed = 1;
+		}
+
+		if (bi->block_state == YAFFS_BLOCK_STATE_NEEDS_SCAN) {
+			/* If we got this far while scanning, then the block
+			 * is fully allocated. */
+			bi->block_state = YAFFS_BLOCK_STATE_FULL;
+		}
+
+		/* Now let's see if it was dirty */
+		if (bi->pages_in_use == 0 &&
+		    !bi->has_shrink_hdr &&
+		    bi->block_state == YAFFS_BLOCK_STATE_FULL) {
+			yaffs_block_became_dirty(dev, blk);
+		}
+	}
+
+	yaffs_skip_rest_of_block(dev);
+
+	if (alt_block_index)
+		vfree(block_index);
+	else
+		kfree(block_index);
+
+	/* Ok, we've done all the scanning.
+	 * Fix up the hard link chains.
+	 * We have scanned all the objects, now it's time to add these
+	 * hardlinks.
+	 */
+	yaffs_link_fixup(dev, &hard_list);
+
+	yaffs_release_temp_buffer(dev, chunk_data);
+
+	if (alloc_failed)
+		return YAFFS_FAIL;
+
+	yaffs_trace(YAFFS_TRACE_SCAN, "yaffs2_scan_backwards ends");
+
+	return YAFFS_OK;
+}
diff --git a/linux-bsp/asm-study/yaffs2/yaffs2/yaffs_yaffs2.h b/linux-bsp/asm-study/yaffs2/yaffs2/yaffs_yaffs2.h
new file mode 100644
index 0000000..2363bfd
--- /dev/null
+++ b/linux-bsp/asm-study/yaffs2/yaffs2/yaffs_yaffs2.h
@@ -0,0 +1,39 @@
+/*
+ * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
+ *
+ * Copyright (C) 2002-2011 Aleph One Ltd.
+ *   for Toby Churchill Ltd and Brightstar Engineering
+ *
+ * Created by Charles Manning <charles@aleph1.co.uk>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 2.1 as
+ * published by the Free Software Foundation.
+ *
+ * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
+ */
+
+#ifndef __YAFFS_YAFFS2_H__
+#define __YAFFS_YAFFS2_H__
+
+#include "yaffs_guts.h"
+
+void yaffs_calc_oldest_dirty_seq(struct yaffs_dev *dev);
+void yaffs2_find_oldest_dirty_seq(struct yaffs_dev *dev);
+void yaffs2_clear_oldest_dirty_seq(struct yaffs_dev *dev,
+				   struct yaffs_block_info *bi);
+void yaffs2_update_oldest_dirty_seq(struct yaffs_dev *dev, unsigned block_no,
+				    struct yaffs_block_info *bi);
+int yaffs_block_ok_for_gc(struct yaffs_dev *dev, struct yaffs_block_info *bi);
+u32 yaffs2_find_refresh_block(struct yaffs_dev *dev);
+int yaffs2_checkpt_required(struct yaffs_dev *dev);
+int yaffs_calc_checkpt_blocks_required(struct yaffs_dev *dev);
+
+void yaffs2_checkpt_invalidate(struct yaffs_dev *dev);
+int yaffs2_checkpt_save(struct yaffs_dev *dev);
+int yaffs2_checkpt_restore(struct yaffs_dev *dev);
+
+int yaffs2_handle_hole(struct yaffs_obj *obj, loff_t new_size);
+int yaffs2_scan_backwards(struct yaffs_dev *dev);
+
+#endif
diff --git a/linux-bsp/asm-study/yaffs2/yaffs2/yaffscfg.h b/linux-bsp/asm-study/yaffs2/yaffs2/yaffscfg.h
new file mode 100644
index 0000000..34235e9
--- /dev/null
+++ b/linux-bsp/asm-study/yaffs2/yaffs2/yaffscfg.h
@@ -0,0 +1,55 @@
+/*
+ * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
+ *
+ * Copyright (C) 2002-2011 Aleph One Ltd.
+ *   for Toby Churchill Ltd and Brightstar Engineering
+ *
+ * Created by Charles Manning <charles@aleph1.co.uk>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 2.1 as
+ * published by the Free Software Foundation.
+ *
+ * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
+ */
+
+/*
+ * Header file for using yaffs in an application via
+ * a direct interface.
+ */
+
+
+#ifndef __YAFFSCFG_H__
+#define __YAFFSCFG_H__
+
+
+#include "yportenv.h"
+
+#define YAFFSFS_N_HANDLES	           100
+#define YAFFSFS_N_DSC	               20
+#define YAFFSFS_MNT_POINT              "/nand"
+
+#define SIZE_1M                        0x100000
+#define YAFFSFS_OFFSET                 (2*SIZE_1M)  /* YAFFS2 file system start offset address */
+#define YAFFSFS_SIZE                   (10*SIZE_1M) /* YAFFS2 file system start offset address */
+
+#define K9F2G08_PAGE_SIZE              2048         /* Nandflash pagesize:  2K */
+#define K9F2G08_BLOCK_SIZE             0x20000      /* Nandflash block size: 128K  */
+#define K9F2G08_SPARE_SIZE             64           /* Nandflash spare area size:  64 */
+
+#define NF_PAGE_SIZE                   K9F2G08_PAGE_SIZE 
+#define NF_BLOCK_SIZE                  K9F2G08_BLOCK_SIZE
+#define NF_SPARE_SIZE                  K9F2G08_SPARE_SIZE
+
+#define YAFFSFS_START_BLOCK            ( YAFFSFS_OFFSET/NF_BLOCK_SIZE )
+#define YAFFSFS_END_BLOCK              ( YAFFSFS_START_BLOCK+(YAFFSFS_SIZE/NF_BLOCK_SIZE) )
+
+
+struct yaffsfs_DeviceConfiguration {
+	const YCHAR *prefix;
+	struct yaffs_dev *dev;
+};
+
+
+#endif
+
diff --git a/linux-bsp/asm-study/yaffs2/yaffs2/yaffscfg2k.c b/linux-bsp/asm-study/yaffs2/yaffs2/yaffscfg2k.c
new file mode 100644
index 0000000..5e4ed9d
--- /dev/null
+++ b/linux-bsp/asm-study/yaffs2/yaffs2/yaffscfg2k.c
@@ -0,0 +1,121 @@
+/*
+ * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
+ *
+ * Copyright (C) 2002-2011 Aleph One Ltd.
+ *   for Toby Churchill Ltd and Brightstar Engineering
+ *
+ * Created by Charles Manning <charles@aleph1.co.uk>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+/*
+ * yaffscfg2k.c  The configuration for the "direct" use of yaffs.
+ *
+ * This file is intended to be modified to your requirements.
+ * There is no need to redistribute this file.
+ */
+
+#include "yaffscfg.h"
+#include "yaffs_guts.h"
+#include "yaffsfs.h"
+#include "yaffs_trace.h"
+#include "yaffs_osglue.h"
+#include "yaffs_k9f2g08.h"
+
+//#include <asm/errno.h>
+//#include <errno.h>
+
+#if 1
+unsigned yaffs_trace_mask =
+
+//	YAFFS_TRACE_SCAN |
+	YAFFS_TRACE_GC |
+//    YAFFS_TRACE_MTD |
+	YAFFS_TRACE_ERASE |
+	YAFFS_TRACE_ERROR |
+//	YAFFS_TRACE_TRACING |
+//	YAFFS_TRACE_ALLOCATE |
+	YAFFS_TRACE_BAD_BLOCKS |
+//	YAFFS_TRACE_VERIFY |
+//    YAFFS_TRACE_ALWAYS |
+	0;
+#else
+unsigned yaffs_trace_mask = 0xFFFFFFFF;
+#endif
+
+
+int yaffs_devconfig(char *_mp, int start_block, int end_block)
+{
+    struct yaffs_dev *dev = NULL;
+    char *mp = NULL;
+
+    dev = malloc(sizeof(*dev));
+    mp = strdup(_mp);
+
+    if (!dev || !mp) 
+    {
+        /*  Alloc error */
+        printf("Failed to allocate memory\n");
+        return -1;
+    }
+
+    /*  Seems sane, so configure */
+    memset(dev, 0, sizeof(*dev));
+    dev->param.name = mp;
+    dev->param.is_yaffs2 = 1;
+
+    dev->param.total_bytes_per_chunk = NF_PAGE_SIZE;
+    dev->param.spare_bytes_per_chunk = NF_SPARE_SIZE;
+    dev->param.chunks_per_block = NF_BLOCK_SIZE / NF_PAGE_SIZE;
+    dev->param.start_block = start_block;
+    dev->param.end_block = end_block;
+    dev->param.n_reserved_blocks = 8;
+
+    dev->param.inband_tags = 0;
+    dev->param.use_nand_ecc = 0;
+    dev->param.no_tags_ecc = 0;
+    dev->param.n_caches=0;
+    dev->param.empty_lost_n_found = 1;
+    dev->param.skip_checkpt_rd = 0;
+    dev->param.skip_checkpt_wr = 0;
+    dev->param.refresh_period = 1000;
+
+    dev->param.initialise_flash_fn = ynf_init;
+    dev->param.erase_fn = ynf_erase_block;
+    dev->param.write_chunk_tags_fn = ynf_write_chunk_tags;
+    dev->param.read_chunk_tags_fn = ynf_read_chunk_tags;
+    dev->param.bad_block_fn = ynf_mark_block_bad;
+    dev->param.query_block_fn = ynf_query_block;
+    dev->driver_context = NULL;
+
+    yaffs_add_device(dev);
+
+    printf("Configures yaffs mount %s: start block %d, end block %d %s\n", 
+            mp, start_block, end_block, dev->param.inband_tags ? "using inband tags" : "");
+    return 0;
+}
+
+
+/* Configure the devices that will be used */
+
+int yaffs_start_up(void)
+{
+	static int start_up_called = 0;
+
+	if(start_up_called)
+		return 0;
+	start_up_called = 1;
+
+    yaffs_devconfig(YAFFSFS_MNT_POINT, YAFFSFS_START_BLOCK, YAFFSFS_END_BLOCK);
+
+	/* Call the OS initialisation (eg. set up lock semaphore */
+	yaffsfs_OSInitialisation();
+
+	return 0;
+}
+
+
+
diff --git a/linux-bsp/asm-study/yaffs2/yaffs2/yaffsfs.c b/linux-bsp/asm-study/yaffs2/yaffs2/yaffsfs.c
new file mode 100644
index 0000000..dbf0557
--- /dev/null
+++ b/linux-bsp/asm-study/yaffs2/yaffs2/yaffsfs.c
@@ -0,0 +1,3461 @@
+/*
+ * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
+ *
+ * Copyright (C) 2002-2011 Aleph One Ltd.
+ *   for Toby Churchill Ltd and Brightstar Engineering
+ *
+ * Created by Charles Manning <charles@aleph1.co.uk>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include "yaffsfs.h"
+#include "yaffs_guts.h"
+#include "yaffscfg.h"
+#include "yportenv.h"
+#include "yaffs_trace.h"
+
+#include "string.h"
+
+#define YAFFSFS_MAX_SYMLINK_DEREFERENCES 5
+
+#ifndef NULL
+#define NULL ((void *)0)
+#endif
+
+/* YAFFSFS_RW_SIZE must be a power of 2 */
+#define YAFFSFS_RW_SHIFT (13)
+#define YAFFSFS_RW_SIZE  (1<<YAFFSFS_RW_SHIFT)
+
+/* Some forward references */
+static struct yaffs_obj *yaffsfs_FindObject(struct yaffs_obj *relativeDirectory,
+					    const YCHAR *path,
+					    int symDepth, int getEquiv,
+					    struct yaffs_obj **dirOut,
+					    int *notDir, int *loop);
+
+static void yaffsfs_RemoveObjectCallback(struct yaffs_obj *obj);
+
+unsigned int yaffs_wr_attempts;
+
+/*
+ * Handle management.
+ * There are open inodes in struct yaffsfs_Inode.
+ * There are open file descriptors in yaffsfs_FileDes.
+ * There are open handles in yaffsfs_FileDes.
+ *
+ * Things are structured this way to be like the Linux VFS model
+ * so that interactions with the yaffs guts calls are similar.
+ * That means more common code paths and less special code.
+ * That means better testing etc.
+ *
+ * We have 3 layers because:
+ * A handle is different than an fd because you can use dup()
+ * to create a new handle that accesses the *same* fd. The two
+ * handles will use the same offset (part of the fd). We only close
+ * down the fd when there are no more handles accessing it.
+ *
+ * More than one fd can currently access one file, but each fd
+ * has its own permsiions and offset.
+ */
+
+struct yaffsfs_Inode {
+	int count;		/* Number of handles accessing this inode */
+	struct yaffs_obj *iObj;
+};
+
+struct yaffsfs_FileDes {
+	u8 reading:1;
+	u8 writing:1;
+	u8 append:1;
+	u8 shareRead:1;
+	u8 shareWrite:1;
+	int inodeId:12;		/* Index to corresponding yaffsfs_Inode */
+	int handleCount:10;	/* Number of handles for this fd */
+	Y_LOFF_T position;	/* current position in file */
+};
+
+struct yaffsfs_Handle {
+	short int fdId;
+	short int useCount;
+};
+
+
+struct yaffsfs_DirSearchContxt {
+	struct yaffs_dirent de;	/* directory entry */
+	YCHAR name[NAME_MAX + 1];	/* name of directory being searched */
+	struct yaffs_obj *dirObj;	/* ptr to directory being searched */
+	struct yaffs_obj *nextReturn;	/* obj  returned by next readddir */
+	struct list_head others;
+	int offset:20;
+	unsigned inUse:1;
+};
+
+static struct yaffsfs_DirSearchContxt yaffsfs_dsc[YAFFSFS_N_DSC];
+static struct yaffsfs_Inode yaffsfs_inode[YAFFSFS_N_HANDLES];
+static struct yaffsfs_FileDes yaffsfs_fd[YAFFSFS_N_HANDLES];
+static struct yaffsfs_Handle yaffsfs_handle[YAFFSFS_N_HANDLES];
+
+static int yaffsfs_handlesInitialised;
+
+unsigned yaffs_set_trace(unsigned tm)
+{
+	yaffs_trace_mask = tm;
+	return yaffs_trace_mask;
+}
+
+unsigned yaffs_get_trace(void)
+{
+	return yaffs_trace_mask;
+}
+
+/*
+ * yaffsfs_InitHandle
+ * Inilitalise handle management on start-up.
+ */
+
+static void yaffsfs_InitHandles(void)
+{
+	int i;
+	if (yaffsfs_handlesInitialised)
+		return;
+
+	memset(yaffsfs_inode, 0, sizeof(yaffsfs_inode));
+	memset(yaffsfs_fd, 0, sizeof(yaffsfs_fd));
+	memset(yaffsfs_handle, 0, sizeof(yaffsfs_handle));
+	memset(yaffsfs_dsc, 0, sizeof(yaffsfs_dsc));
+
+	for (i = 0; i < YAFFSFS_N_HANDLES; i++)
+		yaffsfs_fd[i].inodeId = -1;
+	for (i = 0; i < YAFFSFS_N_HANDLES; i++)
+		yaffsfs_handle[i].fdId = -1;
+}
+
+static struct yaffsfs_Handle *yaffsfs_HandleToPointer(int h)
+{
+	if (h >= 0 && h < YAFFSFS_N_HANDLES)
+		return &yaffsfs_handle[h];
+	return NULL;
+}
+
+static struct yaffsfs_FileDes *yaffsfs_HandleToFileDes(int handle)
+{
+	struct yaffsfs_Handle *h = yaffsfs_HandleToPointer(handle);
+
+	if (h && h->useCount > 0 && h->fdId >= 0 && h->fdId < YAFFSFS_N_HANDLES)
+		return &yaffsfs_fd[h->fdId];
+
+	return NULL;
+}
+
+static struct yaffsfs_Inode *yaffsfs_HandleToInode(int handle)
+{
+	struct yaffsfs_FileDes *fd = yaffsfs_HandleToFileDes(handle);
+
+	if (fd && fd->handleCount > 0 &&
+	    fd->inodeId >= 0 && fd->inodeId < YAFFSFS_N_HANDLES)
+		return &yaffsfs_inode[fd->inodeId];
+
+	return NULL;
+}
+
+static struct yaffs_obj *yaffsfs_HandleToObject(int handle)
+{
+	struct yaffsfs_Inode *in = yaffsfs_HandleToInode(handle);
+
+	if (in)
+		return in->iObj;
+
+	return NULL;
+}
+
+/*
+ * yaffsfs_FindInodeIdForObject
+ * Find the inode entry for an object, if it exists.
+ */
+
+static int yaffsfs_FindInodeIdForObject(struct yaffs_obj *obj)
+{
+	int i;
+	int ret = -1;
+
+	if (obj)
+		obj = yaffs_get_equivalent_obj(obj);
+
+	/* Look for it in open inode table */
+	for (i = 0; i < YAFFSFS_N_HANDLES && ret < 0; i++) {
+		if (yaffsfs_inode[i].iObj == obj)
+			ret = i;
+	}
+	return ret;
+}
+
+/*
+ * yaffsfs_GetInodeIdForObject
+ * Grab an inode entry when opening a new inode.
+ */
+static int yaffsfs_GetInodeIdForObject(struct yaffs_obj *obj)
+{
+	int i;
+	int ret;
+	struct yaffsfs_Inode *in = NULL;
+
+	if (obj)
+		obj = yaffs_get_equivalent_obj(obj);
+
+	ret = yaffsfs_FindInodeIdForObject(obj);
+
+	for (i = 0; i < YAFFSFS_N_HANDLES && ret < 0; i++) {
+		if (!yaffsfs_inode[i].iObj)
+			ret = i;
+	}
+
+	if (ret >= 0) {
+		in = &yaffsfs_inode[ret];
+		if (!in->iObj)
+			in->count = 0;
+		in->iObj = obj;
+		in->count++;
+	}
+
+	return ret;
+}
+
+static int yaffsfs_CountHandles(struct yaffs_obj *obj)
+{
+	int i = yaffsfs_FindInodeIdForObject(obj);
+
+	if (i >= 0)
+		return yaffsfs_inode[i].count;
+	else
+		return 0;
+}
+
+static void yaffsfs_ReleaseInode(struct yaffsfs_Inode *in)
+{
+	struct yaffs_obj *obj;
+
+	obj = in->iObj;
+
+	if (obj->unlinked)
+		yaffs_del_obj(obj);
+
+	obj->my_inode = NULL;
+	in->iObj = NULL;
+
+}
+
+static void yaffsfs_PutInode(int inodeId)
+{
+	if (inodeId >= 0 && inodeId < YAFFSFS_N_HANDLES) {
+		struct yaffsfs_Inode *in = &yaffsfs_inode[inodeId];
+		in->count--;
+		if (in->count <= 0) {
+			yaffsfs_ReleaseInode(in);
+			in->count = 0;
+		}
+	}
+}
+
+static int yaffsfs_NewHandle(struct yaffsfs_Handle **hptr)
+{
+	int i;
+	struct yaffsfs_Handle *h;
+
+	for (i = 0; i < YAFFSFS_N_HANDLES; i++) {
+		h = &yaffsfs_handle[i];
+		if (h->useCount < 1) {
+			memset(h, 0, sizeof(struct yaffsfs_Handle));
+			h->fdId = -1;
+			h->useCount = 1;
+			if (hptr)
+				*hptr = h;
+			return i;
+		}
+	}
+	return -1;
+}
+
+static int yaffsfs_NewHandleAndFileDes(void)
+{
+	int i;
+	struct yaffsfs_FileDes *fd;
+	struct yaffsfs_Handle *h = NULL;
+	int handle = yaffsfs_NewHandle(&h);
+
+	if (handle < 0)
+		return -1;
+
+	for (i = 0; i < YAFFSFS_N_HANDLES; i++) {
+		fd = &yaffsfs_fd[i];
+		if (fd->handleCount < 1) {
+			memset(fd, 0, sizeof(struct yaffsfs_FileDes));
+			fd->inodeId = -1;
+			fd->handleCount = 1;
+			h->fdId = i;
+			return handle;
+		}
+	}
+
+	/* Dump the handle because we could not get a fd */
+	h->useCount = 0;
+	return -1;
+}
+
+/*
+ * yaffs_get_handle
+ * Increase use of handle when reading/writing a file
+ * Also gets the file descriptor.
+ */
+
+static int yaffsfs_GetHandle(int handle)
+{
+	struct yaffsfs_Handle *h = yaffsfs_HandleToPointer(handle);
+
+	if (h && h->useCount > 0) {
+		h->useCount++;
+		return 0;
+	}
+	return -1;
+}
+
+/*
+ * yaffs_put_handle
+ * Let go of a handle when closing a file or aborting an open or
+ * ending a read or write.
+ */
+
+static int yaffsfs_PutFileDes(int fdId)
+{
+	struct yaffsfs_FileDes *fd;
+
+	if (fdId >= 0 && fdId < YAFFSFS_N_HANDLES) {
+		fd = &yaffsfs_fd[fdId];
+		fd->handleCount--;
+		if (fd->handleCount < 1) {
+			if (fd->inodeId >= 0) {
+				yaffsfs_PutInode(fd->inodeId);
+				fd->inodeId = -1;
+			}
+		}
+	}
+	return 0;
+}
+
+static int yaffsfs_PutHandle(int handle)
+{
+	struct yaffsfs_Handle *h = yaffsfs_HandleToPointer(handle);
+
+	if (h && h->useCount > 0) {
+		h->useCount--;
+		if (h->useCount < 1) {
+			yaffsfs_PutFileDes(h->fdId);
+			h->fdId = -1;
+		}
+	}
+
+	return 0;
+}
+
+static void yaffsfs_BreakDeviceHandles(struct yaffs_dev *dev)
+{
+	struct yaffsfs_FileDes *fd;
+	struct yaffsfs_Handle *h;
+	struct yaffs_obj *obj;
+	int i;
+	for (i = 0; i < YAFFSFS_N_HANDLES; i++) {
+		h = yaffsfs_HandleToPointer(i);
+		fd = yaffsfs_HandleToFileDes(i);
+		obj = yaffsfs_HandleToObject(i);
+		if (h && h->useCount > 0) {
+			h->useCount = 0;
+			h->fdId = 0;
+		}
+		if (fd && fd->handleCount > 0 && obj && obj->my_dev == dev) {
+			fd->handleCount = 0;
+			yaffsfs_PutInode(fd->inodeId);
+			fd->inodeId = -1;
+		}
+	}
+}
+
+/*
+ *  Stuff to handle names.
+ */
+#ifdef CONFIG_YAFFS_CASE_INSENSITIVE
+
+static int yaffs_toupper(YCHAR a)
+{
+	if (a >= 'a' && a <= 'z')
+		return (a - 'a') + 'A';
+	else
+		return a;
+}
+
+static int yaffsfs_Match(YCHAR a, YCHAR b)
+{
+	return (yaffs_toupper(a) == yaffs_toupper(b));
+}
+#else
+static int yaffsfs_Match(YCHAR a, YCHAR b)
+{
+	/* case sensitive */
+	return (a == b);
+}
+#endif
+
+static int yaffsfs_IsPathDivider(YCHAR ch)
+{
+	const YCHAR *str = YAFFS_PATH_DIVIDERS;
+
+	while (*str) {
+		if (*str == ch)
+			return 1;
+		str++;
+	}
+
+	return 0;
+}
+
+static int yaffsfs_CheckNameLength(const char *name)
+{
+	int retVal = 0;
+
+	int nameLength = yaffs_strnlen(name, YAFFS_MAX_NAME_LENGTH + 1);
+
+	if (nameLength == 0) {
+		yaffsfs_SetError(-ENOENT);
+		retVal = -1;
+	} else if (nameLength > YAFFS_MAX_NAME_LENGTH) {
+		yaffsfs_SetError(-ENAMETOOLONG);
+		retVal = -1;
+	}
+
+	return retVal;
+}
+
+static int yaffsfs_alt_dir_path(const YCHAR *path, YCHAR **ret_path)
+{
+	YCHAR *alt_path = NULL;
+	int path_length;
+	int i;
+
+	/*
+	 * We don't have a definition for max path length.
+	 * We will use 3 * max name length instead.
+	 */
+	*ret_path = NULL;
+	path_length = yaffs_strnlen(path, (YAFFS_MAX_NAME_LENGTH + 1) * 3 + 1);
+
+	/* If the last character is a path divider, then we need to
+	 * trim it back so that the name look-up works properly.
+	 * eg. /foo/new_dir/ -> /foo/newdir
+	 * Curveball: Need to handle multiple path dividers:
+	 * eg. /foof/sdfse///// -> /foo/sdfse
+	 */
+	if (path_length > 0 && yaffsfs_IsPathDivider(path[path_length - 1])) {
+		alt_path = kmalloc(path_length + 1, 0);
+		if (!alt_path)
+			return -1;
+		yaffs_strcpy(alt_path, path);
+		for (i = path_length - 1;
+		     i >= 0 && yaffsfs_IsPathDivider(alt_path[i]); i--)
+			alt_path[i] = (YCHAR) 0;
+	}
+	*ret_path = alt_path;
+	return 0;
+}
+
+LIST_HEAD(yaffsfs_deviceList);
+
+/*
+ * yaffsfs_FindDevice
+ * yaffsfs_FindRoot
+ * Scan the configuration list to find the device
+ * Curveballs: Should match paths that end in '/' too
+ * Curveball2 Might have "/x/ and "/x/y". Need to return the longest match
+ */
+static struct yaffs_dev *yaffsfs_FindDevice(const YCHAR *path,
+					    YCHAR **restOfPath)
+{
+	struct list_head *cfg;
+	const YCHAR *leftOver;
+	const YCHAR *p;
+	struct yaffs_dev *retval = NULL;
+	struct yaffs_dev *dev = NULL;
+	int thisMatchLength;
+	int longestMatch = -1;
+	int matching;
+
+	/*
+	 * Check all configs, choose the one that:
+	 * 1) Actually matches a prefix (ie /a amd /abc will not match
+	 * 2) Matches the longest.
+	 */
+	list_for_each(cfg, &yaffsfs_deviceList) {
+		dev = list_entry(cfg, struct yaffs_dev, dev_list);
+		leftOver = path;
+		p = dev->param.name;
+		thisMatchLength = 0;
+		matching = 1;
+
+		while (matching && *p && *leftOver) {
+			/* Skip over any /s */
+			while (yaffsfs_IsPathDivider(*p))
+				p++;
+
+			/* Skip over any /s */
+			while (yaffsfs_IsPathDivider(*leftOver))
+				leftOver++;
+
+			/* Now match the text part */
+			while (matching &&
+			       *p && !yaffsfs_IsPathDivider(*p) &&
+			       *leftOver && !yaffsfs_IsPathDivider(*leftOver)) {
+				if (yaffsfs_Match(*p, *leftOver)) {
+					p++;
+					leftOver++;
+					thisMatchLength++;
+				} else {
+					matching = 0;
+				}
+			}
+		}
+
+		/* Skip over any /s in leftOver */
+		while (yaffsfs_IsPathDivider(*leftOver))
+			leftOver++;
+
+		/*Skip over any /s in p */
+		while (yaffsfs_IsPathDivider(*p))
+			p++;
+
+		/* p should now be at the end of the string if fully matched */
+		if (*p)
+			matching = 0;
+
+		if (matching && (thisMatchLength > longestMatch)) {
+			/* Matched prefix */
+			*restOfPath = (YCHAR *) leftOver;
+			retval = dev;
+			longestMatch = thisMatchLength;
+		}
+
+	}
+	return retval;
+}
+
+static int yaffsfs_CheckPath(const YCHAR *path)
+{
+	int n = 0;
+	int divs = 0;
+
+	while (*path && n < YAFFS_MAX_NAME_LENGTH && divs < 100) {
+		if (yaffsfs_IsPathDivider(*path)) {
+			n = 0;
+			divs++;
+		} else
+			n++;
+		path++;
+	}
+
+	return (*path) ? -1 : 0;
+}
+
+/* FindMountPoint only returns a dev entry if the path is a mount point */
+static struct yaffs_dev *yaffsfs_FindMountPoint(const YCHAR *path)
+{
+	struct yaffs_dev *dev;
+	YCHAR *restOfPath = NULL;
+
+	dev = yaffsfs_FindDevice(path, &restOfPath);
+	if (dev && restOfPath && *restOfPath)
+		dev = NULL;
+	return dev;
+}
+
+static struct yaffs_obj *yaffsfs_FindRoot(const YCHAR *path,
+					  YCHAR **restOfPath)
+{
+	struct yaffs_dev *dev;
+
+	dev = yaffsfs_FindDevice(path, restOfPath);
+	if (dev && dev->is_mounted)
+		return dev->root_dir;
+
+	return NULL;
+}
+
+static struct yaffs_obj *yaffsfs_FollowLink(struct yaffs_obj *obj,
+					    int symDepth, int *loop)
+{
+
+	if (obj)
+		obj = yaffs_get_equivalent_obj(obj);
+
+	while (obj && obj->variant_type == YAFFS_OBJECT_TYPE_SYMLINK) {
+		YCHAR *alias = obj->variant.symlink_variant.alias;
+
+		if (yaffsfs_IsPathDivider(*alias))
+			/* Starts with a /, need to scan from root up */
+			obj = yaffsfs_FindObject(NULL, alias, symDepth++,
+						 1, NULL, NULL, loop);
+		else
+			/*
+			 * Relative to here so use the parent of the
+			 * symlink as a start
+			 */
+			obj = yaffsfs_FindObject(obj->parent, alias, symDepth++,
+						 1, NULL, NULL, loop);
+	}
+	return obj;
+}
+
+/*
+ * yaffsfs_FindDirectory
+ * Parse a path to determine the directory and the name within the directory.
+ *
+ * eg. "/data/xx/ff" --> puts name="ff" and returns the directory "/data/xx"
+ */
+static struct yaffs_obj *yaffsfs_DoFindDirectory(struct yaffs_obj *startDir,
+						 const YCHAR *path,
+						 YCHAR **name, int symDepth,
+						 int *notDir, int *loop)
+{
+	struct yaffs_obj *dir;
+	YCHAR *restOfPath;
+	YCHAR str[YAFFS_MAX_NAME_LENGTH + 1];
+	int i;
+
+	if (symDepth > YAFFSFS_MAX_SYMLINK_DEREFERENCES) {
+		if (loop)
+			*loop = 1;
+		return NULL;
+	}
+
+	if (startDir) {
+		dir = startDir;
+		restOfPath = (YCHAR *) path;
+	} else
+		dir = yaffsfs_FindRoot(path, &restOfPath);
+
+	while (dir) {
+		/*
+		 * parse off /.
+		 * curve ball: also throw away surplus '/'
+		 * eg. "/ram/x////ff" gets treated the same as "/ram/x/ff"
+		 */
+		while (yaffsfs_IsPathDivider(*restOfPath))
+			restOfPath++;	/* get rid of '/' */
+
+		*name = restOfPath;
+		i = 0;
+
+		while (*restOfPath && !yaffsfs_IsPathDivider(*restOfPath)) {
+			if (i < YAFFS_MAX_NAME_LENGTH) {
+				str[i] = *restOfPath;
+				str[i + 1] = '\0';
+				i++;
+			}
+			restOfPath++;
+		}
+
+		if (!*restOfPath)
+			/* got to the end of the string */
+			return dir;
+		else {
+			if (yaffs_strcmp(str, _Y(".")) == 0) {
+				/* Do nothing */
+			} else if (yaffs_strcmp(str, _Y("..")) == 0) {
+				dir = dir->parent;
+			} else {
+				dir = yaffs_find_by_name(dir, str);
+
+				dir = yaffsfs_FollowLink(dir, symDepth, loop);
+
+				if (dir && dir->variant_type !=
+				    YAFFS_OBJECT_TYPE_DIRECTORY) {
+					if (notDir)
+						*notDir = 1;
+					dir = NULL;
+				}
+
+			}
+		}
+	}
+	/* directory did not exist. */
+	return NULL;
+}
+
+static struct yaffs_obj *yaffsfs_FindDirectory(struct yaffs_obj *relDir,
+					       const YCHAR *path,
+					       YCHAR **name,
+					       int symDepth,
+					       int *notDir, int *loop)
+{
+	return yaffsfs_DoFindDirectory(relDir, path, name, symDepth, notDir,
+						loop);
+}
+
+/*
+ * yaffsfs_FindObject turns a path for an existing object into the object
+ */
+static struct yaffs_obj *yaffsfs_FindObject(struct yaffs_obj *relDir,
+					    const YCHAR *path, int symDepth,
+					    int getEquiv,
+					    struct yaffs_obj **dirOut,
+					    int *notDir, int *loop)
+{
+	struct yaffs_obj *dir;
+	struct yaffs_obj *obj;
+	YCHAR *name;
+
+	dir =
+	    yaffsfs_FindDirectory(relDir, path, &name, symDepth, notDir, loop);
+
+	if (dirOut)
+		*dirOut = dir;
+
+	if (dir && *name)
+		obj = yaffs_find_by_name(dir, name);
+	else
+		obj = dir;
+
+	if (getEquiv)
+		obj = yaffs_get_equivalent_obj(obj);
+
+	return obj;
+}
+
+/*************************************************************************
+ *	Start of yaffsfs visible functions.
+ *************************************************************************/
+
+int yaffs_dup(int handle)
+{
+	int newHandleNumber = -1;
+	struct yaffsfs_FileDes *existingFD = NULL;
+	struct yaffsfs_Handle *existingHandle = NULL;
+	struct yaffsfs_Handle *newHandle = NULL;
+
+	yaffsfs_Lock();
+	existingHandle = yaffsfs_HandleToPointer(handle);
+	existingFD = yaffsfs_HandleToFileDes(handle);
+	if (existingFD)
+		newHandleNumber = yaffsfs_NewHandle(&newHandle);
+	if (newHandle) {
+		newHandle->fdId = existingHandle->fdId;
+		existingFD->handleCount++;
+	}
+
+	yaffsfs_Unlock();
+
+	if (!existingFD)
+		yaffsfs_SetError(-EBADF);
+	else if (!newHandle)
+		yaffsfs_SetError(-ENOMEM);
+
+	return newHandleNumber;
+
+}
+
+static int yaffsfs_TooManyObjects(struct yaffs_dev *dev)
+{
+	int current_objects = dev->n_obj - dev->n_deleted_files;
+
+	if (dev->param.max_objects && current_objects > dev->param.max_objects)
+		return 1;
+	else
+		return 0;
+}
+
+int yaffs_open_sharing(const YCHAR *path, int oflag, int mode, int sharing)
+{
+	struct yaffs_obj *obj = NULL;
+	struct yaffs_obj *dir = NULL;
+	YCHAR *name;
+	int handle = -1;
+	struct yaffsfs_FileDes *fd = NULL;
+	int openDenied = 0;
+	int symDepth = 0;
+	int errorReported = 0;
+	int rwflags = oflag & (O_RDWR | O_RDONLY | O_WRONLY);
+	u8 shareRead = (sharing & YAFFS_SHARE_READ) ? 1 : 0;
+	u8 shareWrite = (sharing & YAFFS_SHARE_WRITE) ? 1 : 0;
+	u8 sharedReadAllowed;
+	u8 sharedWriteAllowed;
+	u8 alreadyReading;
+	u8 alreadyWriting;
+	u8 readRequested;
+	u8 writeRequested;
+	int notDir = 0;
+	int loop = 0;
+
+	if (!path) {
+		yaffsfs_SetError(-EFAULT);
+		return -1;
+	}
+
+	if (yaffsfs_CheckPath(path) < 0) {
+		yaffsfs_SetError(-ENAMETOOLONG);
+		return -1;
+	}
+
+	/* O_EXCL only has meaning if O_CREAT is specified */
+	if (!(oflag & O_CREAT))
+		oflag &= ~(O_EXCL);
+
+	/* O_TRUNC has no meaning if (O_CREAT | O_EXCL) is specified */
+	if ((oflag & O_CREAT) & (oflag & O_EXCL))
+		oflag &= ~(O_TRUNC);
+
+	/* Todo: Are there any more flag combos to sanitise ? */
+
+	/* Figure out if reading or writing is requested */
+
+	readRequested = (rwflags == O_RDWR || rwflags == O_RDONLY) ? 1 : 0;
+	writeRequested = (rwflags == O_RDWR || rwflags == O_WRONLY) ? 1 : 0;
+
+	yaffsfs_Lock();
+
+	handle = yaffsfs_NewHandleAndFileDes();
+
+	if (handle < 0) {
+		yaffsfs_SetError(-ENFILE);
+		errorReported = 1;
+	} else {
+
+		fd = yaffsfs_HandleToFileDes(handle);
+
+		/* try to find the exisiting object */
+		obj = yaffsfs_FindObject(NULL, path, 0, 1, NULL, NULL, NULL);
+
+		obj = yaffsfs_FollowLink(obj, symDepth++, &loop);
+
+		if (obj &&
+		    obj->variant_type != YAFFS_OBJECT_TYPE_FILE &&
+		    obj->variant_type != YAFFS_OBJECT_TYPE_DIRECTORY)
+			obj = NULL;
+
+		if (obj) {
+
+			/* The file already exists or it might be a directory */
+
+			/* A directory can't be opened as a file */
+			if (obj->variant_type == YAFFS_OBJECT_TYPE_DIRECTORY) {
+				openDenied = 1;
+				yaffsfs_SetError(-EISDIR);
+				errorReported = 1;
+			}
+
+			/* Open should fail if O_CREAT and O_EXCL are specified
+			 * for a file that exists.
+			 */
+			if (!errorReported &&
+			    (oflag & O_EXCL) && (oflag & O_CREAT)) {
+				openDenied = 1;
+				yaffsfs_SetError(-EEXIST);
+				errorReported = 1;
+			}
+
+			/* Check file permissions */
+			if (readRequested && !(obj->yst_mode & S_IREAD))
+				openDenied = 1;
+
+			if (writeRequested && !(obj->yst_mode & S_IWRITE))
+				openDenied = 1;
+
+			if (!errorReported && writeRequested &&
+			    obj->my_dev->read_only) {
+				openDenied = 1;
+				yaffsfs_SetError(-EROFS);
+				errorReported = 1;
+			}
+
+			if (openDenied && !errorReported) {
+				yaffsfs_SetError(-EACCES);
+				errorReported = 1;
+			}
+
+			/* Check sharing of an existing object. */
+			if (!openDenied) {
+				struct yaffsfs_FileDes *fdx;
+				int i;
+
+				sharedReadAllowed = 1;
+				sharedWriteAllowed = 1;
+				alreadyReading = 0;
+				alreadyWriting = 0;
+				for (i = 0; i < YAFFSFS_N_HANDLES; i++) {
+					fdx = &yaffsfs_fd[i];
+					if (fdx->handleCount > 0 &&
+					    fdx->inodeId >= 0 &&
+					    yaffsfs_inode[fdx->inodeId].iObj
+					    == obj) {
+						if (!fdx->shareRead)
+							sharedReadAllowed = 0;
+						if (!fdx->shareWrite)
+							sharedWriteAllowed = 0;
+						if (fdx->reading)
+							alreadyReading = 1;
+						if (fdx->writing)
+							alreadyWriting = 1;
+					}
+				}
+
+				if ((!sharedReadAllowed && readRequested) ||
+				    (!shareRead && alreadyReading) ||
+				    (!sharedWriteAllowed && writeRequested) ||
+				    (!shareWrite && alreadyWriting)) {
+					openDenied = 1;
+					yaffsfs_SetError(-EBUSY);
+					errorReported = 1;
+				}
+			}
+
+		}
+
+		/* If we could not open an existing object, then let's see if
+		 * the directory exists. If not, error.
+		 */
+		if (!obj && !errorReported) {
+			dir = yaffsfs_FindDirectory(NULL, path, &name, 0,
+						    &notDir, &loop);
+			if (!dir && notDir) {
+				yaffsfs_SetError(-ENOTDIR);
+				errorReported = 1;
+			} else if (loop) {
+				yaffsfs_SetError(-ELOOP);
+				errorReported = 1;
+			} else if (!dir) {
+				yaffsfs_SetError(-ENOENT);
+				errorReported = 1;
+			}
+		}
+
+		if (!obj && dir && !errorReported && (oflag & O_CREAT)) {
+			/* Let's see if we can create this file */
+			if (dir->my_dev->read_only) {
+				yaffsfs_SetError(-EROFS);
+				errorReported = 1;
+			} else if (yaffsfs_TooManyObjects(dir->my_dev)) {
+				yaffsfs_SetError(-ENFILE);
+				errorReported = 1;
+			} else
+				obj = yaffs_create_file(dir, name, mode, 0, 0);
+
+			if (!obj && !errorReported) {
+				yaffsfs_SetError(-ENOSPC);
+				errorReported = 1;
+			}
+		}
+
+		if (!obj && dir && !errorReported && !(oflag & O_CREAT)) {
+			yaffsfs_SetError(-ENOENT);
+			errorReported = 1;
+		}
+
+		if (obj && !openDenied) {
+			int inodeId = yaffsfs_GetInodeIdForObject(obj);
+
+			if (inodeId < 0) {
+				/*
+				 * Todo: Fix any problem if inodes run out,
+				 * That can't happen if the number of inode
+				 * items >= number of handles.
+				 */
+			}
+
+			fd->inodeId = inodeId;
+			fd->reading = readRequested;
+			fd->writing = writeRequested;
+			fd->append = (oflag & O_APPEND) ? 1 : 0;
+			fd->position = 0;
+			fd->shareRead = shareRead;
+			fd->shareWrite = shareWrite;
+
+			/* Hook inode to object */
+			obj->my_inode = (void *)&yaffsfs_inode[inodeId];
+
+			if ((oflag & O_TRUNC) && fd->writing)
+				yaffs_resize_file(obj, 0);
+		} else {
+			yaffsfs_PutHandle(handle);
+			if (!errorReported)
+				yaffsfs_SetError(0);	/* Problem */
+			handle = -1;
+		}
+	}
+
+	yaffsfs_Unlock();
+
+	return handle;
+}
+
+int yaffs_open(const YCHAR *path, int oflag, int mode)
+{
+	return yaffs_open_sharing(path, oflag, mode,
+				  YAFFS_SHARE_READ | YAFFS_SHARE_WRITE);
+}
+
+static int yaffs_Dofsync(int handle, int datasync)
+{
+	int retVal = -1;
+	struct yaffs_obj *obj;
+
+	yaffsfs_Lock();
+
+	obj = yaffsfs_HandleToObject(handle);
+
+	if (!obj)
+		yaffsfs_SetError(-EBADF);
+	else if (obj->my_dev->read_only)
+		yaffsfs_SetError(-EROFS);
+	else {
+		yaffs_flush_file(obj, 1, datasync);
+		retVal = 0;
+	}
+
+	yaffsfs_Unlock();
+
+	return retVal;
+}
+
+int yaffs_fsync(int handle)
+{
+	return yaffs_Dofsync(handle, 0);
+}
+
+int yaffs_flush(int handle)
+{
+	return yaffs_fsync(handle);
+}
+
+int yaffs_fdatasync(int handle)
+{
+	return yaffs_Dofsync(handle, 1);
+}
+
+int yaffs_close(int handle)
+{
+	struct yaffsfs_Handle *h = NULL;
+	struct yaffs_obj *obj = NULL;
+	int retVal = -1;
+
+	yaffsfs_Lock();
+
+	h = yaffsfs_HandleToPointer(handle);
+	obj = yaffsfs_HandleToObject(handle);
+
+	if (!h || !obj)
+		yaffsfs_SetError(-EBADF);
+	else {
+		/* clean up */
+		yaffs_flush_file(obj, 1, 0);
+		yaffsfs_PutHandle(handle);
+		retVal = 0;
+	}
+
+	yaffsfs_Unlock();
+
+	return retVal;
+}
+
+static int yaffsfs_do_read(int handle, void *vbuf, unsigned int nbyte,
+		    int isPread, Y_LOFF_T offset)
+{
+	struct yaffsfs_FileDes *fd = NULL;
+	struct yaffs_obj *obj = NULL;
+	Y_LOFF_T pos = 0;
+	Y_LOFF_T startPos = 0;
+	Y_LOFF_T endPos = 0;
+	int nRead = 0;
+	int nToRead = 0;
+	int totalRead = 0;
+	Y_LOFF_T maxRead;
+	u8 *buf = (u8 *) vbuf;
+
+	if (!vbuf) {
+		yaffsfs_SetError(-EFAULT);
+		return -1;
+	}
+
+	yaffsfs_Lock();
+	fd = yaffsfs_HandleToFileDes(handle);
+	obj = yaffsfs_HandleToObject(handle);
+
+	if (!fd || !obj) {
+		/* bad handle */
+		yaffsfs_SetError(-EBADF);
+		totalRead = -1;
+	} else if (!fd->reading) {
+		/* Not a reading handle */
+		yaffsfs_SetError(-EINVAL);
+		totalRead = -1;
+	} else if (nbyte > YAFFS_MAX_FILE_SIZE) {
+		yaffsfs_SetError(-EINVAL);
+		totalRead = -1;
+	} else {
+		if (isPread)
+			startPos = offset;
+		else
+			startPos = fd->position;
+
+		pos = startPos;
+
+		if (yaffs_get_obj_length(obj) > pos)
+			maxRead = yaffs_get_obj_length(obj) - pos;
+		else
+			maxRead = 0;
+
+		if (nbyte > maxRead)
+			nbyte = maxRead;
+
+		yaffsfs_GetHandle(handle);
+
+		endPos = pos + nbyte;
+
+		if (pos < 0 || pos > YAFFS_MAX_FILE_SIZE ||
+		    nbyte > YAFFS_MAX_FILE_SIZE ||
+		    endPos < 0 || endPos > YAFFS_MAX_FILE_SIZE) {
+			totalRead = -1;
+			nbyte = 0;
+		}
+
+		while (nbyte > 0) {
+			nToRead = YAFFSFS_RW_SIZE -
+			    (pos & (YAFFSFS_RW_SIZE - 1));
+			if (nToRead > nbyte)
+				nToRead = nbyte;
+
+			/* Tricky bit...
+			 * Need to reverify object in case the device was
+			 * unmounted in another thread.
+			 */
+			obj = yaffsfs_HandleToObject(handle);
+			if (!obj)
+				nRead = 0;
+			else
+				nRead = yaffs_file_rd(obj, buf, pos, nToRead);
+
+			if (nRead > 0) {
+				totalRead += nRead;
+				pos += nRead;
+				buf += nRead;
+			}
+
+			if (nRead == nToRead)
+				nbyte -= nRead;
+			else
+				nbyte = 0;	/* no more to read */
+
+			if (nbyte > 0) {
+				yaffsfs_Unlock();
+				yaffsfs_Lock();
+			}
+
+		}
+
+		yaffsfs_PutHandle(handle);
+
+		if (!isPread) {
+			if (totalRead >= 0)
+				fd->position = startPos + totalRead;
+			else
+				yaffsfs_SetError(-EINVAL);
+		}
+
+	}
+
+	yaffsfs_Unlock();
+
+	return (totalRead >= 0) ? totalRead : -1;
+
+}
+
+int yaffs_read(int handle, void *buf, unsigned int nbyte)
+{
+	return yaffsfs_do_read(handle, buf, nbyte, 0, 0);
+}
+
+int yaffs_pread(int handle, void *buf, unsigned int nbyte, Y_LOFF_T offset)
+{
+	return yaffsfs_do_read(handle, buf, nbyte, 1, offset);
+}
+
+static int yaffsfs_do_write(int handle, const void *vbuf, unsigned int nbyte,
+		     int isPwrite, Y_LOFF_T offset)
+{
+	struct yaffsfs_FileDes *fd = NULL;
+	struct yaffs_obj *obj = NULL;
+	Y_LOFF_T pos = 0;
+	Y_LOFF_T startPos = 0;
+	Y_LOFF_T endPos;
+	int nWritten = 0;
+	int totalWritten = 0;
+	int write_trhrough = 0;
+	int nToWrite = 0;
+	const u8 *buf = (const u8 *)vbuf;
+
+	if (!vbuf) {
+		yaffsfs_SetError(-EFAULT);
+		return -1;
+	}
+
+	yaffsfs_Lock();
+	fd = yaffsfs_HandleToFileDes(handle);
+	obj = yaffsfs_HandleToObject(handle);
+
+	if (!fd || !obj) {
+		/* bad handle */
+		yaffsfs_SetError(-EBADF);
+		totalWritten = -1;
+	} else if (!fd->writing) {
+		yaffsfs_SetError(-EINVAL);
+		totalWritten = -1;
+	} else if (obj->my_dev->read_only) {
+		yaffsfs_SetError(-EROFS);
+		totalWritten = -1;
+	} else {
+		if (fd->append)
+			startPos = yaffs_get_obj_length(obj);
+		else if (isPwrite)
+			startPos = offset;
+		else
+			startPos = fd->position;
+
+		yaffsfs_GetHandle(handle);
+		pos = startPos;
+		endPos = pos + nbyte;
+
+		if (pos < 0 || pos > YAFFS_MAX_FILE_SIZE ||
+		    nbyte > YAFFS_MAX_FILE_SIZE ||
+		    endPos < 0 || endPos > YAFFS_MAX_FILE_SIZE) {
+			totalWritten = -1;
+			nbyte = 0;
+		}
+
+		while (nbyte > 0) {
+
+			nToWrite = YAFFSFS_RW_SIZE -
+			    (pos & (YAFFSFS_RW_SIZE - 1));
+			if (nToWrite > nbyte)
+				nToWrite = nbyte;
+
+			/* Tricky bit...
+			 * Need to reverify object in case the device was
+			 * remounted or unmounted in another thread.
+			 */
+			obj = yaffsfs_HandleToObject(handle);
+			if (!obj || obj->my_dev->read_only)
+				nWritten = 0;
+			else
+				nWritten =
+				    yaffs_wr_file(obj, buf, pos, nToWrite,
+						  write_trhrough);
+			if (nWritten > 0) {
+				totalWritten += nWritten;
+				pos += nWritten;
+				buf += nWritten;
+			}
+
+			if (nWritten == nToWrite)
+				nbyte -= nToWrite;
+			else
+				nbyte = 0;
+
+			if (nWritten < 1 && totalWritten < 1) {
+				yaffsfs_SetError(-ENOSPC);
+				totalWritten = -1;
+			}
+
+			if (nbyte > 0) {
+				yaffsfs_Unlock();
+				yaffsfs_Lock();
+			}
+		}
+
+		yaffsfs_PutHandle(handle);
+
+		if (!isPwrite) {
+			if (totalWritten > 0)
+				fd->position = startPos + totalWritten;
+			else
+				yaffsfs_SetError(-EINVAL);
+		}
+	}
+
+	yaffsfs_Unlock();
+
+	return (totalWritten >= 0) ? totalWritten : -1;
+}
+
+int yaffs_write(int fd, const void *buf, unsigned int nbyte)
+{
+	return yaffsfs_do_write(fd, buf, nbyte, 0, 0);
+}
+
+int yaffs_pwrite(int fd, const void *buf, unsigned int nbyte, Y_LOFF_T offset)
+{
+	return yaffsfs_do_write(fd, buf, nbyte, 1, offset);
+}
+
+int yaffs_truncate(const YCHAR *path, Y_LOFF_T new_size)
+{
+	struct yaffs_obj *obj = NULL;
+	struct yaffs_obj *dir = NULL;
+	int result = YAFFS_FAIL;
+	int notDir = 0;
+	int loop = 0;
+
+	if (!path) {
+		yaffsfs_SetError(-EFAULT);
+		return -1;
+	}
+
+	if (yaffsfs_CheckPath(path) < 0) {
+		yaffsfs_SetError(-ENAMETOOLONG);
+		return -1;
+	}
+
+	yaffsfs_Lock();
+
+	obj = yaffsfs_FindObject(NULL, path, 0, 1, &dir, &notDir, &loop);
+	obj = yaffsfs_FollowLink(obj, 0, &loop);
+
+	if (!dir && notDir)
+		yaffsfs_SetError(-ENOTDIR);
+	else if (loop)
+		yaffsfs_SetError(-ELOOP);
+	else if (!dir || !obj)
+		yaffsfs_SetError(-ENOENT);
+	else if (obj->my_dev->read_only)
+		yaffsfs_SetError(-EROFS);
+	else if (obj->variant_type != YAFFS_OBJECT_TYPE_FILE)
+		yaffsfs_SetError(-EISDIR);
+	else if (obj->my_dev->read_only)
+		yaffsfs_SetError(-EROFS);
+	else if (new_size < 0 || new_size > YAFFS_MAX_FILE_SIZE)
+		yaffsfs_SetError(-EINVAL);
+	else
+		result = yaffs_resize_file(obj, new_size);
+
+	yaffsfs_Unlock();
+
+	return (result) ? 0 : -1;
+}
+
+int yaffs_ftruncate(int handle, Y_LOFF_T new_size)
+{
+	struct yaffsfs_FileDes *fd = NULL;
+	struct yaffs_obj *obj = NULL;
+	int result = 0;
+
+	yaffsfs_Lock();
+	fd = yaffsfs_HandleToFileDes(handle);
+	obj = yaffsfs_HandleToObject(handle);
+
+	if (!fd || !obj)
+		/* bad handle */
+		yaffsfs_SetError(-EBADF);
+	else if (!fd->writing)
+		yaffsfs_SetError(-EINVAL);
+	else if (obj->my_dev->read_only)
+		yaffsfs_SetError(-EROFS);
+	else if (new_size < 0 || new_size > YAFFS_MAX_FILE_SIZE)
+		yaffsfs_SetError(-EINVAL);
+	else
+		/* resize the file */
+		result = yaffs_resize_file(obj, new_size);
+	yaffsfs_Unlock();
+
+	return (result) ? 0 : -1;
+
+}
+
+Y_LOFF_T yaffs_lseek(int handle, Y_LOFF_T offset, int whence)
+{
+	struct yaffsfs_FileDes *fd = NULL;
+	struct yaffs_obj *obj = NULL;
+	Y_LOFF_T pos = -1;
+	Y_LOFF_T fSize = -1;
+
+	yaffsfs_Lock();
+	fd = yaffsfs_HandleToFileDes(handle);
+	obj = yaffsfs_HandleToObject(handle);
+
+	if (!fd || !obj)
+		yaffsfs_SetError(-EBADF);
+	else if (offset > YAFFS_MAX_FILE_SIZE)
+		yaffsfs_SetError(-EINVAL);
+	else {
+		if (whence == SEEK_SET) {
+			if (offset >= 0)
+				pos = offset;
+		} else if (whence == SEEK_CUR) {
+			if ((fd->position + offset) >= 0)
+				pos = (fd->position + offset);
+		} else if (whence == SEEK_END) {
+			fSize = yaffs_get_obj_length(obj);
+			if (fSize >= 0 && (fSize + offset) >= 0)
+				pos = fSize + offset;
+		}
+
+		if (pos >= 0 && pos <= YAFFS_MAX_FILE_SIZE)
+			fd->position = pos;
+		else {
+			yaffsfs_SetError(-EINVAL);
+			pos = -1;
+		}
+	}
+
+	yaffsfs_Unlock();
+
+	return pos;
+}
+
+static int yaffsfs_DoUnlink(const YCHAR *path, int isDirectory)
+{
+	struct yaffs_obj *dir = NULL;
+	struct yaffs_obj *obj = NULL;
+	YCHAR *name;
+	int result = YAFFS_FAIL;
+	int notDir = 0;
+	int loop = 0;
+
+	if (!path) {
+		yaffsfs_SetError(-EFAULT);
+		return -1;
+	}
+
+	if (yaffsfs_CheckPath(path) < 0) {
+		yaffsfs_SetError(-ENAMETOOLONG);
+		return -1;
+	}
+
+	yaffsfs_Lock();
+
+	obj = yaffsfs_FindObject(NULL, path, 0, 0, NULL, NULL, NULL);
+	dir = yaffsfs_FindDirectory(NULL, path, &name, 0, &notDir, &loop);
+
+	if (!dir && notDir)
+		yaffsfs_SetError(-ENOTDIR);
+	else if (loop)
+		yaffsfs_SetError(-ELOOP);
+	else if (!dir)
+		yaffsfs_SetError(-ENOENT);
+	else if (yaffs_strncmp(name, _Y("."), 2) == 0)
+		yaffsfs_SetError(-EINVAL);
+	else if (!obj)
+		yaffsfs_SetError(-ENOENT);
+	else if (obj->my_dev->read_only)
+		yaffsfs_SetError(-EROFS);
+	else if (!isDirectory &&
+		 obj->variant_type == YAFFS_OBJECT_TYPE_DIRECTORY)
+		yaffsfs_SetError(-EISDIR);
+	else if (isDirectory &&
+		 obj->variant_type != YAFFS_OBJECT_TYPE_DIRECTORY)
+		yaffsfs_SetError(-ENOTDIR);
+	else if (isDirectory && obj == obj->my_dev->root_dir)
+		yaffsfs_SetError(-EBUSY);	/* Can't rmdir a root */
+	else {
+		result = yaffs_unlinker(dir, name);
+
+		if (result == YAFFS_FAIL && isDirectory)
+			yaffsfs_SetError(-ENOTEMPTY);
+	}
+
+	yaffsfs_Unlock();
+
+	return (result == YAFFS_FAIL) ? -1 : 0;
+}
+
+int yaffs_unlink(const YCHAR *path)
+{
+	return yaffsfs_DoUnlink(path, 0);
+}
+
+char* last_char_is(const char *s, int c)
+{
+    if (s && *s) 
+    { 
+        size_t sz = strlen(s) - 1;
+        s += sz;
+        if ( (unsigned char)*s == c)
+            return (char*)s;
+    }
+    
+    return NULL;
+}  
+
+#define DOT_OR_DOTDOT(s) ((s)[0] == '.' && (!(s)[1] || ((s)[1] == '.' && !(s)[2])))
+char* concat_subpath_file(const char *path, const char *filename)
+{           
+    YCHAR *new_path = NULL;
+    int path_length;
+    char *lc;
+
+    if (filename && DOT_OR_DOTDOT(filename))
+        return NULL; 
+
+    if (!path)
+        path = "";
+
+    /*
+     * We don't have a definition for max path length.
+     * We will use 3 * max name length instead.
+     */
+    path_length = yaffs_strnlen(path, (YAFFS_MAX_NAME_LENGTH + 1) * 3 + 1);
+    new_path = kmalloc(path_length + 1, 0);
+    if(!new_path)
+        return NULL;
+
+    memset(new_path, 0, path_length+1);
+
+    lc = last_char_is(path, '/');
+    while (*filename == '/')
+        filename++;
+
+    sprintf(new_path, "%s%s%s", path, (lc==NULL ? "/" : ""), filename);
+    return new_path;
+}    
+
+/* Implement of ls by guowenxue, 2013.05.30 */
+int yaffs_ls(const char *dname, int recursive)
+{
+    yaffs_DIR *d;
+    struct yaffs_dirent *de;
+    struct yaffs_stat s;
+    char prefix[5];
+    int  rv = 0;
+
+    memset(prefix, 0, sizeof(prefix));
+
+    if( ! (d=yaffs_opendir(dname)) )
+    {
+        yaffs_trace(YAFFS_TRACE_ERROR, "Open '%s' failure: %s", dname, yaffs_perror());
+        return -1;
+    }
+
+    while((de = yaffs_readdir(d)) != NULL)
+    {
+        char *file_path;
+        file_path = concat_subpath_file(dname, de->d_name);
+        if( yaffs_lstat(file_path, &s) < 0)
+        {
+            yaffs_trace(YAFFS_TRACE_ERROR, "yaffs: Could not stat '%s'", file_path);
+            yaffs_set_error(-ENOENT);
+            rv = -1;
+            free(file_path);
+            break;
+        }
+        
+        /* Setup file mode  */
+        switch(s.st_mode & S_IFMT)
+        {
+            case S_IFREG:
+                prefix[0]='-'; 
+                break;
+            case S_IFDIR: 
+                prefix[0]='d'; 
+                break;
+            case S_IFLNK:
+                prefix[0]='l'; 
+                break;
+            default: 
+                prefix[0]='u'; 
+                break;
+        }
+
+        /* Setup RWX mode  */
+        if(s.st_mode & S_IREAD)
+            prefix[1]='r';
+        else
+            prefix[1]='-';
+
+        if(s.st_mode & S_IWRITE)
+            prefix[2]='w';
+        else
+            prefix[2]='-';
+
+        if(s.st_mode & S_IEXEC)
+            prefix[3]='x';
+        else
+            prefix[3]='-';
+
+        printf("%s %d %s %d bytes\n", prefix, s.st_nlink, file_path, (int)s.st_size);
+        if((s.st_mode & S_IFMT) == S_IFDIR && recursive)
+        {
+            yaffs_ls(file_path, recursive);
+        }
+        free(file_path);
+    }
+
+    yaffs_closedir(d);
+
+    //printf("Free space in %s is %d\n\n",dname,(int)yaffs_freespace(dname));
+    return rv;
+}
+
+/* Implement of rm -rf by guowenxue, 2013.05.30 */
+int yaffs_rm(const YCHAR *path, int recursive)
+{
+    struct yaffs_stat path_stat;
+
+    if( yaffs_lstat(path, &path_stat) < 0)
+    {
+        yaffs_trace(YAFFS_TRACE_ERROR, "yaffs: Could not stat '%s'", path);
+        yaffs_set_error(-ENOENT);
+        return -1;
+    }
+
+    if(S_ISDIR(path_stat.st_mode) )
+    {
+        yaffs_DIR           *dp = NULL;
+        struct yaffs_dirent *de = NULL;
+
+        /* Only can remove empty folder  */
+        if( !recursive ) 
+            return yaffs_rmdir(path);
+
+        if ( ! (dp=yaffs_opendir(path)) )
+        {
+            return -1;
+        }
+
+        /* Remove all the file in current directory */
+        while ((de = yaffs_readdir(dp)) != NULL) 
+        {
+             char *new_path;
+             new_path = concat_subpath_file(path, de->d_name);
+             if (new_path == NULL)
+                 continue;
+
+             if (yaffs_rm(new_path, recursive) < 0)
+             {
+                 free(new_path);
+                 yaffs_closedir(dp);
+                 return -1;
+             }
+
+             free(new_path);
+        }
+
+        /* Remove the left empty folder */
+        yaffs_closedir(dp);
+
+        if (yaffs_rmdir(path) < 0) 
+        { 
+            yaffs_trace(YAFFS_TRACE_ERROR, "can't remove '%s': %s", path, yaffs_perror());
+            return -1;
+        }
+
+        return 0;
+    }
+    
+    /* Not directory */
+    return yaffs_unlink(path);
+}
+
+int yaffs_rename(const YCHAR *oldPath, const YCHAR *newPath)
+{
+	struct yaffs_obj *olddir = NULL;
+	struct yaffs_obj *newdir = NULL;
+	struct yaffs_obj *obj = NULL;
+	struct yaffs_obj *newobj = NULL;
+	YCHAR *oldname;
+	YCHAR *newname;
+	int result = YAFFS_FAIL;
+	int rename_allowed = 1;
+	int notOldDir = 0;
+	int notNewDir = 0;
+	int oldLoop = 0;
+	int newLoop = 0;
+
+	YCHAR *alt_newpath = NULL;
+
+	if (!oldPath || !newPath) {
+		yaffsfs_SetError(-EFAULT);
+		return -1;
+	}
+
+	if (yaffsfs_CheckPath(oldPath) < 0 || yaffsfs_CheckPath(newPath) < 0) {
+		yaffsfs_SetError(-ENAMETOOLONG);
+		return -1;
+	}
+
+	if (yaffsfs_alt_dir_path(newPath, &alt_newpath) < 0) {
+		yaffsfs_SetError(-ENOMEM);
+		return -1;
+	}
+	if (alt_newpath)
+		newPath = alt_newpath;
+
+	yaffsfs_Lock();
+
+	olddir = yaffsfs_FindDirectory(NULL, oldPath, &oldname, 0,
+				       &notOldDir, &oldLoop);
+	newdir = yaffsfs_FindDirectory(NULL, newPath, &newname, 0,
+				       &notNewDir, &newLoop);
+	obj = yaffsfs_FindObject(NULL, oldPath, 0, 0, NULL, NULL, NULL);
+	newobj = yaffsfs_FindObject(NULL, newPath, 0, 0, NULL, NULL, NULL);
+
+	/* If the object being renamed is a directory and the
+	 * path ended with a "/" then the olddir == obj.
+	 * We pass through NULL for the old name to tell the lower layers
+	 * to use olddir as the object.
+	 */
+
+	if (olddir == obj)
+		oldname = NULL;
+
+	if ((!olddir && notOldDir) || (!newdir && notNewDir)) {
+		yaffsfs_SetError(-ENOTDIR);
+		rename_allowed = 0;
+	} else if (oldLoop || newLoop) {
+		yaffsfs_SetError(-ELOOP);
+		rename_allowed = 0;
+	} else if (olddir && oldname &&
+			yaffs_strncmp(oldname, _Y("."), 2) == 0) {
+		yaffsfs_SetError(-EINVAL);
+		rename_allowed = 0;
+	} else if (!olddir || !newdir || !obj) {
+		yaffsfs_SetError(-ENOENT);
+		rename_allowed = 0;
+	} else if (obj->my_dev->read_only) {
+		yaffsfs_SetError(-EROFS);
+		rename_allowed = 0;
+	} else if (yaffs_is_non_empty_dir(newobj)) {
+		yaffsfs_SetError(-ENOTEMPTY);
+		rename_allowed = 0;
+	} else if (olddir->my_dev != newdir->my_dev) {
+		/* Rename must be on same device */
+		yaffsfs_SetError(-EXDEV);
+		rename_allowed = 0;
+	} else if (obj && obj->variant_type == YAFFS_OBJECT_TYPE_DIRECTORY) {
+		/*
+		 * It is a directory, check that it is not being renamed to
+		 * being its own decendent.
+		 * Do this by tracing from the new directory back to the root,
+		 * checking for obj
+		 */
+
+		struct yaffs_obj *xx = newdir;
+
+		while (rename_allowed && xx) {
+			if (xx == obj)
+				rename_allowed = 0;
+			xx = xx->parent;
+		}
+		if (!rename_allowed)
+			yaffsfs_SetError(-EINVAL);
+	}
+
+	if (rename_allowed)
+		result = yaffs_rename_obj(olddir, oldname, newdir, newname);
+
+	yaffsfs_Unlock();
+
+	kfree(alt_newpath);
+
+	return (result == YAFFS_FAIL) ? -1 : 0;
+}
+
+static int yaffsfs_DoStat(struct yaffs_obj *obj, struct yaffs_stat *buf)
+{
+	int retVal = -1;
+
+	obj = yaffs_get_equivalent_obj(obj);
+
+	if (obj && buf) {
+		buf->st_dev = (int)obj->my_dev->os_context;
+		buf->st_ino = obj->obj_id;
+		buf->st_mode = obj->yst_mode & ~S_IFMT;
+
+		if (obj->variant_type == YAFFS_OBJECT_TYPE_DIRECTORY)
+			buf->st_mode |= S_IFDIR;
+		else if (obj->variant_type == YAFFS_OBJECT_TYPE_SYMLINK)
+			buf->st_mode |= S_IFLNK;
+		else if (obj->variant_type == YAFFS_OBJECT_TYPE_FILE)
+			buf->st_mode |= S_IFREG;
+
+		buf->st_nlink = yaffs_get_obj_link_count(obj);
+		buf->st_uid = 0;
+		buf->st_gid = 0;
+		buf->st_rdev = obj->yst_rdev;
+		buf->st_size = yaffs_get_obj_length(obj);
+		buf->st_blksize = obj->my_dev->data_bytes_per_chunk;
+		buf->st_blocks = (buf->st_size + buf->st_blksize - 1) /
+		    buf->st_blksize;
+#if CONFIG_YAFFS_WINCE
+		buf->yst_wince_atime[0] = obj->win_atime[0];
+		buf->yst_wince_atime[1] = obj->win_atime[1];
+		buf->yst_wince_ctime[0] = obj->win_ctime[0];
+		buf->yst_wince_ctime[1] = obj->win_ctime[1];
+		buf->yst_wince_mtime[0] = obj->win_mtime[0];
+		buf->yst_wince_mtime[1] = obj->win_mtime[1];
+#else
+		buf->yst_atime = obj->yst_atime;
+		buf->yst_ctime = obj->yst_ctime;
+		buf->yst_mtime = obj->yst_mtime;
+#endif
+		retVal = 0;
+	}
+	return retVal;
+}
+
+static int yaffsfs_DoStatOrLStat(const YCHAR *path,
+				 struct yaffs_stat *buf, int doLStat)
+{
+	struct yaffs_obj *obj = NULL;
+	struct yaffs_obj *dir = NULL;
+	int retVal = -1;
+	int notDir = 0;
+	int loop = 0;
+
+	if (!path || !buf) {
+		yaffsfs_SetError(-EFAULT);
+		return -1;
+	}
+
+	if (yaffsfs_CheckPath(path) < 0) {
+		yaffsfs_SetError(-ENAMETOOLONG);
+		return -1;
+	}
+
+	yaffsfs_Lock();
+
+	obj = yaffsfs_FindObject(NULL, path, 0, 1, &dir, &notDir, &loop);
+
+	if (!doLStat && obj)
+		obj = yaffsfs_FollowLink(obj, 0, &loop);
+
+	if (!dir && notDir)
+		yaffsfs_SetError(-ENOTDIR);
+	else if (loop)
+		yaffsfs_SetError(-ELOOP);
+	else if (!dir || !obj)
+		yaffsfs_SetError(-ENOENT);
+	else
+		retVal = yaffsfs_DoStat(obj, buf);
+
+	yaffsfs_Unlock();
+
+	return retVal;
+
+}
+
+int yaffs_stat(const YCHAR *path, struct yaffs_stat *buf)
+{
+	return yaffsfs_DoStatOrLStat(path, buf, 0);
+}
+
+int yaffs_lstat(const YCHAR *path, struct yaffs_stat *buf)
+{
+	return yaffsfs_DoStatOrLStat(path, buf, 1);
+}
+
+int yaffs_fstat(int fd, struct yaffs_stat *buf)
+{
+	struct yaffs_obj *obj;
+
+	int retVal = -1;
+
+	if (!buf) {
+		yaffsfs_SetError(-EFAULT);
+		return -1;
+	}
+
+	yaffsfs_Lock();
+	obj = yaffsfs_HandleToObject(fd);
+
+	if (obj)
+		retVal = yaffsfs_DoStat(obj, buf);
+	else
+		/* bad handle */
+		yaffsfs_SetError(-EBADF);
+
+	yaffsfs_Unlock();
+
+	return retVal;
+}
+
+static int yaffsfs_DoUtime(struct yaffs_obj *obj,
+			   const struct yaffs_utimbuf *buf)
+{
+	int retVal = -1;
+	int result;
+
+	struct yaffs_utimbuf local;
+
+	obj = yaffs_get_equivalent_obj(obj);
+
+	if (obj && obj->my_dev->read_only) {
+		yaffsfs_SetError(-EROFS);
+		return -1;
+	}
+
+	if (!buf) {
+		local.actime = Y_CURRENT_TIME;
+		local.modtime = local.actime;
+		buf = &local;
+	}
+
+	if (obj) {
+		obj->yst_atime = buf->actime;
+		obj->yst_mtime = buf->modtime;
+		obj->dirty = 1;
+		result = yaffs_flush_file(obj, 0, 0);
+		retVal = result == YAFFS_OK ? 0 : -1;
+	}
+
+	return retVal;
+}
+
+int yaffs_utime(const YCHAR *path, const struct yaffs_utimbuf *buf)
+{
+	struct yaffs_obj *obj = NULL;
+	struct yaffs_obj *dir = NULL;
+	int retVal = -1;
+	int notDir = 0;
+	int loop = 0;
+
+	if (!path) {
+		yaffsfs_SetError(-EFAULT);
+		return -1;
+	}
+
+	if (yaffsfs_CheckPath(path) < 0) {
+		yaffsfs_SetError(-ENAMETOOLONG);
+		return -1;
+	}
+
+	yaffsfs_Lock();
+
+	obj = yaffsfs_FindObject(NULL, path, 0, 1, &dir, &notDir, &loop);
+
+	if (!dir && notDir)
+		yaffsfs_SetError(-ENOTDIR);
+	else if (loop)
+		yaffsfs_SetError(-ELOOP);
+	else if (!dir || !obj)
+		yaffsfs_SetError(-ENOENT);
+	else
+		retVal = yaffsfs_DoUtime(obj, buf);
+
+	yaffsfs_Unlock();
+
+	return retVal;
+
+}
+
+int yaffs_futime(int fd, const struct yaffs_utimbuf *buf)
+{
+	struct yaffs_obj *obj;
+
+	int retVal = -1;
+
+	yaffsfs_Lock();
+	obj = yaffsfs_HandleToObject(fd);
+
+	if (obj)
+		retVal = yaffsfs_DoUtime(obj, buf);
+	else
+		/* bad handle */
+		yaffsfs_SetError(-EBADF);
+
+	yaffsfs_Unlock();
+
+	return retVal;
+}
+
+#ifndef CONFIG_YAFFS_WINCE
+/* xattrib functions */
+
+static int yaffs_do_setxattr(const YCHAR *path, const char *name,
+			     const void *data, int size, int flags, int follow)
+{
+	struct yaffs_obj *obj;
+	struct yaffs_obj *dir;
+	int notDir = 0;
+	int loop = 0;
+
+	int retVal = -1;
+
+	if (!path || !name || !data) {
+		yaffsfs_SetError(-EFAULT);
+		return -1;
+	}
+
+	if (yaffsfs_CheckPath(path) < 0) {
+		yaffsfs_SetError(-ENAMETOOLONG);
+		return -1;
+	}
+
+	yaffsfs_Lock();
+
+	obj = yaffsfs_FindObject(NULL, path, 0, 1, &dir, &notDir, &loop);
+
+	if (follow)
+		obj = yaffsfs_FollowLink(obj, 0, &loop);
+
+	if (!dir && notDir)
+		yaffsfs_SetError(-ENOTDIR);
+	else if (loop)
+		yaffsfs_SetError(-ELOOP);
+	else if (!dir || !obj)
+		yaffsfs_SetError(-ENOENT);
+	else {
+		retVal = yaffs_set_xattrib(obj, name, data, size, flags);
+		if (retVal < 0) {
+			yaffsfs_SetError(retVal);
+			retVal = -1;
+		}
+	}
+
+	yaffsfs_Unlock();
+
+	return retVal;
+
+}
+
+int yaffs_setxattr(const YCHAR *path, const char *name,
+		   const void *data, int size, int flags)
+{
+	return yaffs_do_setxattr(path, name, data, size, flags, 1);
+}
+
+int yaffs_lsetxattr(const YCHAR *path, const char *name,
+		    const void *data, int size, int flags)
+{
+	return yaffs_do_setxattr(path, name, data, size, flags, 0);
+}
+
+int yaffs_fsetxattr(int fd, const char *name,
+		    const void *data, int size, int flags)
+{
+	struct yaffs_obj *obj;
+
+	int retVal = -1;
+
+	if (!name || !data) {
+		yaffsfs_SetError(-EFAULT);
+		return -1;
+	}
+
+	yaffsfs_Lock();
+	obj = yaffsfs_HandleToObject(fd);
+
+	if (!obj)
+		yaffsfs_SetError(-EBADF);
+	else {
+		retVal = yaffs_set_xattrib(obj, name, data, size, flags);
+		if (retVal < 0) {
+			yaffsfs_SetError(retVal);
+			retVal = -1;
+		}
+	}
+
+	yaffsfs_Unlock();
+
+	return retVal;
+}
+
+static int yaffs_do_getxattr(const YCHAR *path, const char *name,
+			     void *data, int size, int follow)
+{
+	struct yaffs_obj *obj;
+	struct yaffs_obj *dir;
+	int retVal = -1;
+	int notDir = 0;
+	int loop = 0;
+
+	if (!path || !name || !data) {
+		yaffsfs_SetError(-EFAULT);
+		return -1;
+	}
+
+	if (yaffsfs_CheckPath(path) < 0) {
+		yaffsfs_SetError(-ENAMETOOLONG);
+		return -1;
+	}
+
+	yaffsfs_Lock();
+
+	obj = yaffsfs_FindObject(NULL, path, 0, 1, &dir, &notDir, &loop);
+
+	if (follow)
+		obj = yaffsfs_FollowLink(obj, 0, &loop);
+
+	if (!dir && notDir)
+		yaffsfs_SetError(-ENOTDIR);
+	else if (loop)
+		yaffsfs_SetError(-ELOOP);
+	else if (!dir || !obj)
+		yaffsfs_SetError(-ENOENT);
+	else {
+		retVal = yaffs_get_xattrib(obj, name, data, size);
+		if (retVal < 0) {
+			yaffsfs_SetError(retVal);
+			retVal = -1;
+		}
+	}
+	yaffsfs_Unlock();
+
+	return retVal;
+
+}
+
+int yaffs_getxattr(const YCHAR *path, const char *name, void *data, int size)
+{
+	return yaffs_do_getxattr(path, name, data, size, 1);
+}
+
+int yaffs_lgetxattr(const YCHAR *path, const char *name, void *data, int size)
+{
+	return yaffs_do_getxattr(path, name, data, size, 0);
+}
+
+int yaffs_fgetxattr(int fd, const char *name, void *data, int size)
+{
+	struct yaffs_obj *obj;
+
+	int retVal = -1;
+
+	if (!name || !data) {
+		yaffsfs_SetError(-EFAULT);
+		return -1;
+	}
+
+	yaffsfs_Lock();
+	obj = yaffsfs_HandleToObject(fd);
+
+	if (obj) {
+		retVal = yaffs_get_xattrib(obj, name, data, size);
+		if (retVal < 0) {
+			yaffsfs_SetError(retVal);
+			retVal = -1;
+		}
+	} else
+		/* bad handle */
+		yaffsfs_SetError(-EBADF);
+
+	yaffsfs_Unlock();
+
+	return retVal;
+}
+
+static int yaffs_do_listxattr(const YCHAR *path, char *data,
+			      int size, int follow)
+{
+	struct yaffs_obj *obj = NULL;
+	struct yaffs_obj *dir = NULL;
+	int retVal = -1;
+	int notDir = 0;
+	int loop = 0;
+
+	if (!path || !data) {
+		yaffsfs_SetError(-EFAULT);
+		return -1;
+	}
+
+	if (yaffsfs_CheckPath(path) < 0) {
+		yaffsfs_SetError(-ENAMETOOLONG);
+		return -1;
+	}
+
+	yaffsfs_Lock();
+
+	obj = yaffsfs_FindObject(NULL, path, 0, 1, &dir, &notDir, &loop);
+
+	if (follow)
+		obj = yaffsfs_FollowLink(obj, 0, &loop);
+
+	if (!dir && notDir)
+		yaffsfs_SetError(-ENOTDIR);
+	else if (loop)
+		yaffsfs_SetError(-ELOOP);
+	else if (!dir || !obj)
+		yaffsfs_SetError(-ENOENT);
+	else {
+		retVal = yaffs_list_xattrib(obj, data, size);
+		if (retVal < 0) {
+			yaffsfs_SetError(retVal);
+			retVal = -1;
+		}
+	}
+
+	yaffsfs_Unlock();
+
+	return retVal;
+
+}
+
+int yaffs_listxattr(const YCHAR *path, char *data, int size)
+{
+	return yaffs_do_listxattr(path, data, size, 1);
+}
+
+int yaffs_llistxattr(const YCHAR *path, char *data, int size)
+{
+	return yaffs_do_listxattr(path, data, size, 0);
+}
+
+int yaffs_flistxattr(int fd, char *data, int size)
+{
+	struct yaffs_obj *obj;
+
+	int retVal = -1;
+
+	if (!data) {
+		yaffsfs_SetError(-EFAULT);
+		return -1;
+	}
+
+	yaffsfs_Lock();
+	obj = yaffsfs_HandleToObject(fd);
+
+	if (obj) {
+		retVal = yaffs_list_xattrib(obj, data, size);
+		if (retVal < 0) {
+			yaffsfs_SetError(retVal);
+			retVal = -1;
+		}
+	} else
+		/* bad handle */
+		yaffsfs_SetError(-EBADF);
+
+	yaffsfs_Unlock();
+
+	return retVal;
+}
+
+static int yaffs_do_removexattr(const YCHAR *path, const char *name,
+				int follow)
+{
+	struct yaffs_obj *obj = NULL;
+	struct yaffs_obj *dir = NULL;
+	int notDir = 0;
+	int loop = 0;
+	int retVal = -1;
+
+	if (!path || !name) {
+		yaffsfs_SetError(-EFAULT);
+		return -1;
+	}
+
+	if (yaffsfs_CheckPath(path) < 0) {
+		yaffsfs_SetError(-ENAMETOOLONG);
+		return -1;
+	}
+
+	yaffsfs_Lock();
+
+	obj = yaffsfs_FindObject(NULL, path, 0, 1, &dir, &notDir, &loop);
+
+	if (follow)
+		obj = yaffsfs_FollowLink(obj, 0, &loop);
+
+	if (!dir && notDir)
+		yaffsfs_SetError(-ENOTDIR);
+	else if (loop)
+		yaffsfs_SetError(-ELOOP);
+	else if (!dir || !obj)
+		yaffsfs_SetError(-ENOENT);
+	else {
+		retVal = yaffs_remove_xattrib(obj, name);
+		if (retVal < 0) {
+			yaffsfs_SetError(retVal);
+			retVal = -1;
+		}
+	}
+
+	yaffsfs_Unlock();
+
+	return retVal;
+
+}
+
+int yaffs_removexattr(const YCHAR *path, const char *name)
+{
+	return yaffs_do_removexattr(path, name, 1);
+}
+
+int yaffs_lremovexattr(const YCHAR *path, const char *name)
+{
+	return yaffs_do_removexattr(path, name, 0);
+}
+
+int yaffs_fremovexattr(int fd, const char *name)
+{
+	struct yaffs_obj *obj;
+
+	int retVal = -1;
+
+	if (!name) {
+		yaffsfs_SetError(-EFAULT);
+		return -1;
+	}
+
+	yaffsfs_Lock();
+	obj = yaffsfs_HandleToObject(fd);
+
+	if (obj) {
+		retVal = yaffs_remove_xattrib(obj, name);
+		if (retVal < 0) {
+			yaffsfs_SetError(retVal);
+			retVal = -1;
+		}
+	} else
+		/* bad handle */
+		yaffsfs_SetError(-EBADF);
+
+	yaffsfs_Unlock();
+
+	return retVal;
+}
+#endif
+
+#ifdef CONFIG_YAFFS_WINCE
+int yaffs_get_wince_times(int fd, unsigned *wctime,
+			  unsigned *watime, unsigned *wmtime)
+{
+	struct yaffs_obj *obj;
+
+	int retVal = -1;
+
+	yaffsfs_Lock();
+	obj = yaffsfs_HandleToObject(fd);
+
+	if (obj) {
+
+		if (wctime) {
+			wctime[0] = obj->win_ctime[0];
+			wctime[1] = obj->win_ctime[1];
+		}
+		if (watime) {
+			watime[0] = obj->win_atime[0];
+			watime[1] = obj->win_atime[1];
+		}
+		if (wmtime) {
+			wmtime[0] = obj->win_mtime[0];
+			wmtime[1] = obj->win_mtime[1];
+		}
+
+		retVal = 0;
+	} else
+		/*  bad handle */
+		yaffsfs_SetError(-EBADF);
+
+	yaffsfs_Unlock();
+
+	return retVal;
+}
+
+int yaffs_set_wince_times(int fd,
+			  const unsigned *wctime,
+			  const unsigned *watime, const unsigned *wmtime)
+{
+	struct yaffs_obj *obj;
+	int result;
+	int retVal = -1;
+
+	yaffsfs_Lock();
+	obj = yaffsfs_HandleToObject(fd);
+
+	if (obj) {
+
+		if (wctime) {
+			obj->win_ctime[0] = wctime[0];
+			obj->win_ctime[1] = wctime[1];
+		}
+		if (watime) {
+			obj->win_atime[0] = watime[0];
+			obj->win_atime[1] = watime[1];
+		}
+		if (wmtime) {
+			obj->win_mtime[0] = wmtime[0];
+			obj->win_mtime[1] = wmtime[1];
+		}
+
+		obj->dirty = 1;
+		result = yaffs_flush_file(obj, 0, 0);
+		retVal = 0;
+	} else
+		/* bad handle */
+		yaffsfs_SetError(-EBADF);
+
+	yaffsfs_Unlock();
+
+	return retVal;
+}
+
+#endif
+
+static int yaffsfs_DoChMod(struct yaffs_obj *obj, mode_t mode)
+{
+	int result = -1;
+
+	if (obj)
+		obj = yaffs_get_equivalent_obj(obj);
+
+	if (obj) {
+		obj->yst_mode = mode;
+		obj->dirty = 1;
+		result = yaffs_flush_file(obj, 0, 0);
+	}
+
+	return result == YAFFS_OK ? 0 : -1;
+}
+
+int yaffs_access(const YCHAR *path, int amode)
+{
+	struct yaffs_obj *obj = NULL;
+	struct yaffs_obj *dir = NULL;
+	int notDir = 0;
+	int loop = 0;
+	int retval = -1;
+
+	if (!path) {
+		yaffsfs_SetError(-EFAULT);
+		return -1;
+	}
+
+	if (yaffsfs_CheckPath(path) < 0) {
+		yaffsfs_SetError(-ENAMETOOLONG);
+		return -1;
+	}
+
+	if (amode & ~(R_OK | W_OK | X_OK)) {
+		yaffsfs_SetError(-EINVAL);
+		return -1;
+	}
+
+	yaffsfs_Lock();
+
+	obj = yaffsfs_FindObject(NULL, path, 0, 1, &dir, &notDir, &loop);
+	obj = yaffsfs_FollowLink(obj, 0, &loop);
+
+	if (!dir && notDir)
+		yaffsfs_SetError(-ENOTDIR);
+	else if (loop)
+		yaffsfs_SetError(-ELOOP);
+	else if (!dir || !obj)
+		yaffsfs_SetError(-ENOENT);
+	else if ((amode & W_OK) && obj->my_dev->read_only)
+		yaffsfs_SetError(-EROFS);
+	else {
+		int access_ok = 1;
+
+		if ((amode & R_OK) && !(obj->yst_mode & S_IREAD))
+			access_ok = 0;
+		if ((amode & W_OK) && !(obj->yst_mode & S_IWRITE))
+			access_ok = 0;
+		if ((amode & X_OK) && !(obj->yst_mode & S_IEXEC))
+			access_ok = 0;
+
+		if (!access_ok)
+			yaffsfs_SetError(-EACCES);
+		else
+			retval = 0;
+	}
+
+	yaffsfs_Unlock();
+
+	return retval;
+
+}
+
+int yaffs_chmod(const YCHAR *path, mode_t mode)
+{
+	struct yaffs_obj *obj = NULL;
+	struct yaffs_obj *dir = NULL;
+	int retVal = -1;
+	int notDir = 0;
+	int loop = 0;
+
+	if (!path) {
+		yaffsfs_SetError(-EFAULT);
+		return -1;
+	}
+
+	if (yaffsfs_CheckPath(path) < 0) {
+		yaffsfs_SetError(-ENAMETOOLONG);
+		return -1;
+	}
+
+	if (mode & ~(0777)) {
+		yaffsfs_SetError(-EINVAL);
+		return -1;
+	}
+
+	yaffsfs_Lock();
+
+	obj = yaffsfs_FindObject(NULL, path, 0, 1, &dir, &notDir, &loop);
+	obj = yaffsfs_FollowLink(obj, 0, &loop);
+
+	if (!dir && notDir)
+		yaffsfs_SetError(-ENOTDIR);
+	else if (loop)
+		yaffsfs_SetError(-ELOOP);
+	else if (!dir || !obj)
+		yaffsfs_SetError(-ENOENT);
+	else if (obj->my_dev->read_only)
+		yaffsfs_SetError(-EROFS);
+	else
+		retVal = yaffsfs_DoChMod(obj, mode);
+
+	yaffsfs_Unlock();
+
+	return retVal;
+
+}
+
+int yaffs_fchmod(int fd, mode_t mode)
+{
+	struct yaffs_obj *obj;
+	int retVal = -1;
+
+	if (mode & ~(0777)) {
+		yaffsfs_SetError(-EINVAL);
+		return -1;
+	}
+
+	yaffsfs_Lock();
+	obj = yaffsfs_HandleToObject(fd);
+
+	if (!obj)
+		yaffsfs_SetError(-EBADF);
+	else if (obj->my_dev->read_only)
+		yaffsfs_SetError(-EROFS);
+	else
+		retVal = yaffsfs_DoChMod(obj, mode);
+
+	yaffsfs_Unlock();
+
+	return retVal;
+}
+
+int yaffs_mkdir(const YCHAR *path, mode_t mode)
+{
+	struct yaffs_obj *parent = NULL;
+	struct yaffs_obj *dir = NULL;
+	YCHAR *name;
+	YCHAR *alt_path = NULL;
+	int retVal = -1;
+	int notDir = 0;
+	int loop = 0;
+
+	if (!path) {
+		yaffsfs_SetError(-EFAULT);
+		return -1;
+	}
+
+	if (yaffsfs_CheckPath(path) < 0) {
+		yaffsfs_SetError(-ENAMETOOLONG);
+		return -1;
+	}
+
+	if (yaffsfs_alt_dir_path(path, &alt_path) < 0) {
+		yaffsfs_SetError(-ENOMEM);
+		return -1;
+	}
+	if (alt_path)
+		path = alt_path;
+
+	yaffsfs_Lock();
+	parent = yaffsfs_FindDirectory(NULL, path, &name, 0, &notDir, &loop);
+	if (!parent && notDir)
+		yaffsfs_SetError(-ENOTDIR);
+	else if (loop)
+		yaffsfs_SetError(-ELOOP);
+	else if (!parent)
+		yaffsfs_SetError(-ENOENT);
+	else if (yaffsfs_TooManyObjects(parent->my_dev))
+		yaffsfs_SetError(-ENFILE);
+	else if (yaffs_strnlen(name, 5) == 0) {
+		/* Trying to make the root itself */
+		yaffsfs_SetError(-EEXIST);
+	} else if (parent->my_dev->read_only)
+		yaffsfs_SetError(-EROFS);
+	else {
+		dir = yaffs_create_dir(parent, name, mode, 0, 0);
+		if (dir)
+			retVal = 0;
+		else if (yaffs_find_by_name(parent, name))
+			yaffsfs_SetError(-EEXIST);	/* name exists */
+		else
+			yaffsfs_SetError(-ENOSPC);	/* assume no space */
+	}
+
+	yaffsfs_Unlock();
+
+	kfree(alt_path);
+
+	return retVal;
+}
+
+int yaffs_rmdir(const YCHAR *path)
+{
+	int result;
+	YCHAR *alt_path;
+
+	if (!path) {
+		yaffsfs_SetError(-EFAULT);
+		return -1;
+	}
+
+	if (yaffsfs_CheckPath(path) < 0) {
+		yaffsfs_SetError(-ENAMETOOLONG);
+		return -1;
+	}
+
+	if (yaffsfs_alt_dir_path(path, &alt_path) < 0) {
+		yaffsfs_SetError(-ENOMEM);
+		return -1;
+	}
+	if (alt_path)
+		path = alt_path;
+	result = yaffsfs_DoUnlink(path, 1);
+
+	kfree(alt_path);
+
+	return result;
+}
+
+void *yaffs_getdev(const YCHAR *path)
+{
+	struct yaffs_dev *dev = NULL;
+	YCHAR *dummy;
+	dev = yaffsfs_FindDevice(path, &dummy);
+	return (void *)dev;
+}
+
+int yaffs_mount_common(const YCHAR *path, int read_only, int skip_checkpt)
+{
+	int retVal = -1;
+	int result = YAFFS_FAIL;
+	struct yaffs_dev *dev = NULL;
+
+	if (!path) {
+		yaffsfs_SetError(-EFAULT);
+		return -1;
+	}
+
+	yaffs_trace(YAFFS_TRACE_MOUNT, "yaffs: Mounting %s", path);
+
+	if (yaffsfs_CheckPath(path) < 0) {
+		yaffsfs_SetError(-ENAMETOOLONG);
+		return -1;
+	}
+
+	yaffsfs_Lock();
+
+	yaffsfs_InitHandles();
+
+	dev = yaffsfs_FindMountPoint(path);
+	if (dev) {
+		if (!dev->is_mounted) {
+			dev->read_only = read_only ? 1 : 0;
+			if (skip_checkpt) {
+				u8 skip = dev->param.skip_checkpt_rd;
+				dev->param.skip_checkpt_rd = 1;
+				result = yaffs_guts_initialise(dev);
+				dev->param.skip_checkpt_rd = skip;
+			} else {
+				result = yaffs_guts_initialise(dev);
+			}
+
+			if (result == YAFFS_FAIL)
+				yaffsfs_SetError(-ENOMEM);
+			retVal = result ? 0 : -1;
+
+		} else
+			yaffsfs_SetError(-EBUSY);
+	} else
+		yaffsfs_SetError(-ENODEV);
+
+	yaffsfs_Unlock();
+	return retVal;
+
+}
+
+int yaffs_mount2(const YCHAR *path, int readonly)
+{
+	return yaffs_mount_common(path, readonly, 0);
+}
+
+int yaffs_mount(const YCHAR *path)
+{
+	return yaffs_mount_common(path, 0, 0);
+}
+
+int yaffs_sync(const YCHAR *path)
+{
+	int retVal = -1;
+	struct yaffs_dev *dev = NULL;
+	YCHAR *dummy;
+
+	if (!path) {
+		yaffsfs_SetError(-EFAULT);
+		return -1;
+	}
+
+	if (yaffsfs_CheckPath(path) < 0) {
+		yaffsfs_SetError(-ENAMETOOLONG);
+		return -1;
+	}
+
+	yaffsfs_Lock();
+	dev = yaffsfs_FindDevice(path, &dummy);
+	if (dev) {
+		if (!dev->is_mounted)
+			yaffsfs_SetError(-EINVAL);
+		else if (dev->read_only)
+			yaffsfs_SetError(-EROFS);
+		else {
+
+			yaffs_flush_whole_cache(dev);
+			yaffs_checkpoint_save(dev);
+			retVal = 0;
+
+		}
+	} else
+		yaffsfs_SetError(-ENODEV);
+
+	yaffsfs_Unlock();
+	return retVal;
+}
+
+static int yaffsfs_IsDevBusy(struct yaffs_dev *dev)
+{
+	int i;
+	struct yaffs_obj *obj;
+
+	for (i = 0; i < YAFFSFS_N_HANDLES; i++) {
+		obj = yaffsfs_HandleToObject(i);
+		if (obj && obj->my_dev == dev)
+			return 1;
+	}
+	return 0;
+}
+
+int yaffs_remount(const YCHAR *path, int force, int read_only)
+{
+	int retVal = -1;
+	struct yaffs_dev *dev = NULL;
+
+	if (!path) {
+		yaffsfs_SetError(-EFAULT);
+		return -1;
+	}
+
+	if (yaffsfs_CheckPath(path) < 0) {
+		yaffsfs_SetError(-ENAMETOOLONG);
+		return -1;
+	}
+
+	yaffsfs_Lock();
+	dev = yaffsfs_FindMountPoint(path);
+	if (dev) {
+		if (dev->is_mounted) {
+			yaffs_flush_whole_cache(dev);
+
+			if (force || !yaffsfs_IsDevBusy(dev)) {
+				if (read_only)
+					yaffs_checkpoint_save(dev);
+				dev->read_only = read_only ? 1 : 0;
+				retVal = 0;
+			} else
+				yaffsfs_SetError(-EBUSY);
+
+		} else
+			yaffsfs_SetError(-EINVAL);
+
+	} else
+		yaffsfs_SetError(-ENODEV);
+
+	yaffsfs_Unlock();
+	return retVal;
+
+}
+
+int yaffs_unmount2(const YCHAR *path, int force)
+{
+	int retVal = -1;
+	struct yaffs_dev *dev = NULL;
+
+	if (!path) {
+		yaffsfs_SetError(-EFAULT);
+		return -1;
+	}
+
+	if (yaffsfs_CheckPath(path) < 0) {
+		yaffsfs_SetError(-ENAMETOOLONG);
+		return -1;
+	}
+
+	yaffsfs_Lock();
+	dev = yaffsfs_FindMountPoint(path);
+	if (dev) {
+		if (dev->is_mounted) {
+			int inUse;
+			yaffs_flush_whole_cache(dev);
+			yaffs_checkpoint_save(dev);
+			inUse = yaffsfs_IsDevBusy(dev);
+			if (!inUse || force) {
+				if (inUse)
+					yaffsfs_BreakDeviceHandles(dev);
+				yaffs_deinitialise(dev);
+
+				retVal = 0;
+			} else
+				yaffsfs_SetError(-EBUSY);
+
+		} else
+			yaffsfs_SetError(-EINVAL);
+
+	} else
+		yaffsfs_SetError(-ENODEV);
+
+	yaffsfs_Unlock();
+	return retVal;
+
+}
+
+int yaffs_unmount(const YCHAR *path)
+{
+	return yaffs_unmount2(path, 0);
+}
+
+int yaffs_format(const YCHAR *path,
+		int unmount_flag,
+		int force_unmount_flag,
+		int remount_flag)
+{
+	int retVal = 0;
+	struct yaffs_dev *dev = NULL;
+	int result;
+
+	if (!path) {
+		yaffsfs_SetError(-EFAULT);
+		return -1;
+	}
+
+	if (yaffsfs_CheckPath(path) < 0) {
+		yaffsfs_SetError(-ENAMETOOLONG);
+		return -1;
+	}
+
+	yaffsfs_Lock();
+	dev = yaffsfs_FindMountPoint(path);
+
+	if (dev) {
+		int was_mounted = dev->is_mounted;
+
+		if (dev->is_mounted && unmount_flag) {
+			int inUse;
+			yaffs_flush_whole_cache(dev);
+			yaffs_checkpoint_save(dev);
+			inUse = yaffsfs_IsDevBusy(dev);
+			if (!inUse || force_unmount_flag) {
+				if (inUse)
+					yaffsfs_BreakDeviceHandles(dev);
+				yaffs_deinitialise(dev);
+			}
+		}
+
+		if(dev->is_mounted) {
+				yaffsfs_SetError(-EBUSY);
+				retVal = -1;
+		} else {
+			yaffs_format_dev(dev);
+			if(was_mounted && remount_flag) {
+				result = yaffs_guts_initialise(dev);
+				if (result == YAFFS_FAIL) {
+					yaffsfs_SetError(-ENOMEM);
+					retVal = -1;
+				}
+			}
+		}
+	} else {
+		yaffsfs_SetError(-ENODEV);
+		retVal = -1;
+	}
+
+	yaffsfs_Unlock();
+	return retVal;
+
+}
+
+
+Y_LOFF_T yaffs_freespace(const YCHAR *path)
+{
+	Y_LOFF_T retVal = -1;
+	struct yaffs_dev *dev = NULL;
+	YCHAR *dummy;
+
+	if (!path) {
+		yaffsfs_SetError(-EFAULT);
+		return -1;
+	}
+
+	if (yaffsfs_CheckPath(path) < 0) {
+		yaffsfs_SetError(-ENAMETOOLONG);
+		return -1;
+	}
+
+	yaffsfs_Lock();
+	dev = yaffsfs_FindDevice(path, &dummy);
+	if (dev && dev->is_mounted) {
+		retVal = yaffs_get_n_free_chunks(dev);
+		retVal *= dev->data_bytes_per_chunk;
+
+	} else
+		yaffsfs_SetError(-EINVAL);
+
+	yaffsfs_Unlock();
+	return retVal;
+}
+
+Y_LOFF_T yaffs_totalspace(const YCHAR *path)
+{
+	Y_LOFF_T retVal = -1;
+	struct yaffs_dev *dev = NULL;
+	YCHAR *dummy;
+
+	if (!path) {
+		yaffsfs_SetError(-EFAULT);
+		return -1;
+	}
+
+	if (yaffsfs_CheckPath(path) < 0) {
+		yaffsfs_SetError(-ENAMETOOLONG);
+		return -1;
+	}
+
+	yaffsfs_Lock();
+	dev = yaffsfs_FindDevice(path, &dummy);
+	if (dev && dev->is_mounted) {
+		retVal = (dev->param.end_block - dev->param.start_block + 1) -
+		    dev->param.n_reserved_blocks;
+		retVal *= dev->param.chunks_per_block;
+		retVal *= dev->data_bytes_per_chunk;
+
+	} else
+		yaffsfs_SetError(-EINVAL);
+
+	yaffsfs_Unlock();
+	return retVal;
+}
+
+int yaffs_inodecount(const YCHAR *path)
+{
+	Y_LOFF_T retVal = -1;
+	struct yaffs_dev *dev = NULL;
+	YCHAR *dummy;
+
+	if (!path) {
+		yaffsfs_SetError(-EFAULT);
+		return -1;
+	}
+
+	if (yaffsfs_CheckPath(path) < 0) {
+		yaffsfs_SetError(-ENAMETOOLONG);
+		return -1;
+	}
+
+	yaffsfs_Lock();
+	dev = yaffsfs_FindDevice(path, &dummy);
+	if (dev && dev->is_mounted) {
+		int n_obj = dev->n_obj;
+		if (n_obj > dev->n_hardlinks)
+			retVal = n_obj - dev->n_hardlinks;
+	}
+
+	if (retVal < 0)
+		yaffsfs_SetError(-EINVAL);
+
+	yaffsfs_Unlock();
+	return retVal;
+}
+
+void yaffs_add_device(struct yaffs_dev *dev)
+{
+	struct list_head *cfg;
+	/* First check that the device is not in the list. */
+
+	list_for_each(cfg, &yaffsfs_deviceList) {
+		if (dev == list_entry(cfg, struct yaffs_dev, dev_list))
+			return;
+	}
+
+	dev->is_mounted = 0;
+	dev->param.remove_obj_fn = yaffsfs_RemoveObjectCallback;
+
+	if (!dev->dev_list.next)
+		INIT_LIST_HEAD(&dev->dev_list);
+
+	list_add(&dev->dev_list, &yaffsfs_deviceList);
+}
+
+void yaffs_remove_device(struct yaffs_dev *dev)
+{
+	list_del_init(&dev->dev_list);
+}
+
+/* Functions to iterate through devices. NB Use with extreme care! */
+
+static struct list_head *dev_iterator;
+void yaffs_dev_rewind(void)
+{
+	dev_iterator = yaffsfs_deviceList.next;
+}
+
+struct yaffs_dev *yaffs_next_dev(void)
+{
+	struct yaffs_dev *retval;
+
+	if (!dev_iterator)
+		return NULL;
+	if (dev_iterator == &yaffsfs_deviceList)
+		return NULL;
+
+	retval = list_entry(dev_iterator, struct yaffs_dev, dev_list);
+	dev_iterator = dev_iterator->next;
+	return retval;
+}
+
+/* Directory search stuff. */
+
+static struct list_head search_contexts;
+
+static void yaffsfs_SetDirRewound(struct yaffsfs_DirSearchContxt *dsc)
+{
+	if (dsc &&
+	    dsc->dirObj &&
+	    dsc->dirObj->variant_type == YAFFS_OBJECT_TYPE_DIRECTORY) {
+
+		dsc->offset = 0;
+
+		if (list_empty(&dsc->dirObj->variant.dir_variant.children))
+			dsc->nextReturn = NULL;
+		else
+			dsc->nextReturn =
+			    list_entry(dsc->dirObj->variant.dir_variant.
+				       children.next, struct yaffs_obj,
+				       siblings);
+	} else {
+		/* Hey someone isn't playing nice! */
+	}
+}
+
+static void yaffsfs_DirAdvance(struct yaffsfs_DirSearchContxt *dsc)
+{
+	if (dsc &&
+	    dsc->dirObj &&
+	    dsc->dirObj->variant_type == YAFFS_OBJECT_TYPE_DIRECTORY) {
+
+		if (dsc->nextReturn == NULL ||
+		    list_empty(&dsc->dirObj->variant.dir_variant.children))
+			dsc->nextReturn = NULL;
+		else {
+			struct list_head *next = dsc->nextReturn->siblings.next;
+
+			if (next == &dsc->dirObj->variant.dir_variant.children)
+				dsc->nextReturn = NULL;	/* end of list */
+			else
+				dsc->nextReturn = list_entry(next,
+							     struct yaffs_obj,
+							     siblings);
+		}
+	} else {
+		/* Hey someone isn't playing nice! */
+	}
+}
+
+static void yaffsfs_RemoveObjectCallback(struct yaffs_obj *obj)
+{
+
+	struct list_head *i;
+	struct yaffsfs_DirSearchContxt *dsc;
+
+	/* if search contexts not initilised then skip */
+	if (!search_contexts.next)
+		return;
+
+	/* Iterate through the directory search contexts.
+	 * If any are the one being removed, then advance the dsc to
+	 * the next one to prevent a hanging ptr.
+	 */
+	list_for_each(i, &search_contexts) {
+		if (i) {
+			dsc = list_entry(i, struct yaffsfs_DirSearchContxt,
+					 others);
+			if (dsc->nextReturn == obj)
+				yaffsfs_DirAdvance(dsc);
+		}
+	}
+
+}
+
+yaffs_DIR *yaffs_opendir(const YCHAR *dirname)
+{
+	yaffs_DIR *dir = NULL;
+	struct yaffs_obj *obj = NULL;
+	struct yaffsfs_DirSearchContxt *dsc = NULL;
+	int notDir = 0;
+	int loop = 0;
+
+	if (!dirname) {
+		yaffsfs_SetError(-EFAULT);
+		return NULL;
+	}
+
+	if (yaffsfs_CheckPath(dirname) < 0) {
+		yaffsfs_SetError(-ENAMETOOLONG);
+		return NULL;
+	}
+
+	yaffsfs_Lock();
+
+	obj = yaffsfs_FindObject(NULL, dirname, 0, 1, NULL, &notDir, &loop);
+
+	if (!obj && notDir)
+		yaffsfs_SetError(-ENOTDIR);
+	else if (loop)
+		yaffsfs_SetError(-ELOOP);
+	else if (!obj)
+		yaffsfs_SetError(-ENOENT);
+	else if (obj->variant_type != YAFFS_OBJECT_TYPE_DIRECTORY)
+		yaffsfs_SetError(-ENOTDIR);
+	else {
+		int i;
+
+		for (i = 0, dsc = NULL; i < YAFFSFS_N_DSC && !dsc; i++) {
+			if (!yaffsfs_dsc[i].inUse)
+				dsc = &yaffsfs_dsc[i];
+		}
+
+		dir = (yaffs_DIR *) dsc;
+
+		if (dsc) {
+			memset(dsc, 0, sizeof(struct yaffsfs_DirSearchContxt));
+			dsc->inUse = 1;
+			dsc->dirObj = obj;
+			yaffs_strncpy(dsc->name, dirname, NAME_MAX);
+			INIT_LIST_HEAD(&dsc->others);
+
+			if (!search_contexts.next)
+				INIT_LIST_HEAD(&search_contexts);
+
+			list_add(&dsc->others, &search_contexts);
+			yaffsfs_SetDirRewound(dsc);
+		}
+
+	}
+
+	yaffsfs_Unlock();
+
+	return dir;
+}
+
+struct yaffs_dirent *yaffs_readdir(yaffs_DIR * dirp)
+{
+	struct yaffsfs_DirSearchContxt *dsc;
+	struct yaffs_dirent *retVal = NULL;
+
+	dsc = (struct yaffsfs_DirSearchContxt *) dirp;
+	yaffsfs_Lock();
+
+	if (dsc && dsc->inUse) {
+		yaffsfs_SetError(0);
+		if (dsc->nextReturn) {
+			dsc->de.d_ino =
+			    yaffs_get_equivalent_obj(dsc->nextReturn)->obj_id;
+			dsc->de.d_dont_use = (unsigned)dsc->nextReturn;
+			dsc->de.d_off = dsc->offset++;
+			yaffs_get_obj_name(dsc->nextReturn,
+					   dsc->de.d_name, NAME_MAX);
+			if (yaffs_strnlen(dsc->de.d_name, NAME_MAX + 1) == 0) {
+				/* this should not happen! */
+				yaffs_strcpy(dsc->de.d_name, _Y("zz"));
+			}
+			dsc->de.d_reclen = sizeof(struct yaffs_dirent);
+			retVal = &dsc->de;
+			yaffsfs_DirAdvance(dsc);
+		} else
+			retVal = NULL;
+	} else
+		yaffsfs_SetError(-EBADF);
+
+	yaffsfs_Unlock();
+
+	return retVal;
+
+}
+
+void yaffs_rewinddir(yaffs_DIR *dirp)
+{
+	struct yaffsfs_DirSearchContxt *dsc;
+
+	dsc = (struct yaffsfs_DirSearchContxt *) dirp;
+
+	yaffsfs_Lock();
+
+	yaffsfs_SetDirRewound(dsc);
+
+	yaffsfs_Unlock();
+}
+
+int yaffs_closedir(yaffs_DIR *dirp)
+{
+	struct yaffsfs_DirSearchContxt *dsc;
+
+	dsc = (struct yaffsfs_DirSearchContxt *) dirp;
+
+	if (!dsc) {
+		yaffsfs_SetError(-EFAULT);
+		return -1;
+	}
+
+	yaffsfs_Lock();
+	dsc->inUse = 0;
+	list_del(&dsc->others);	/* unhook from list */
+	yaffsfs_Unlock();
+	return 0;
+}
+
+/* End of directory stuff */
+
+int yaffs_symlink(const YCHAR *oldpath, const YCHAR *newpath)
+{
+	struct yaffs_obj *parent = NULL;
+	struct yaffs_obj *obj;
+	YCHAR *name;
+	int retVal = -1;
+	int mode = 0;		/* ignore for now */
+	int notDir = 0;
+	int loop = 0;
+
+	if (!oldpath || !newpath) {
+		yaffsfs_SetError(-EFAULT);
+		return -1;
+	}
+
+	if (yaffsfs_CheckPath(newpath) < 0 || yaffsfs_CheckPath(oldpath) < 0) {
+		yaffsfs_SetError(-ENAMETOOLONG);
+		return -1;
+	}
+
+	yaffsfs_Lock();
+	parent = yaffsfs_FindDirectory(NULL, newpath, &name, 0, &notDir, &loop);
+	if (!parent && notDir)
+		yaffsfs_SetError(-ENOTDIR);
+	else if (loop)
+		yaffsfs_SetError(-ELOOP);
+	else if (!parent || yaffs_strnlen(name, 5) < 1)
+		yaffsfs_SetError(-ENOENT);
+	else if (yaffsfs_TooManyObjects(parent->my_dev))
+		yaffsfs_SetError(-ENFILE);
+	else if (parent->my_dev->read_only)
+		yaffsfs_SetError(-EROFS);
+	else if (parent) {
+		obj = yaffs_create_symlink(parent, name, mode, 0, 0, oldpath);
+		if (obj)
+			retVal = 0;
+		else if (yaffsfs_FindObject
+			 (NULL, newpath, 0, 0, NULL, NULL, NULL))
+			yaffsfs_SetError(-EEXIST);
+		else
+			yaffsfs_SetError(-ENOSPC);
+	}
+
+	yaffsfs_Unlock();
+
+	return retVal;
+
+}
+
+int yaffs_readlink(const YCHAR *path, YCHAR *buf, int bufsiz)
+{
+	struct yaffs_obj *obj = NULL;
+	struct yaffs_obj *dir = NULL;
+	int retVal = -1;
+	int notDir = 0;
+	int loop = 0;
+
+	if (!path || !buf) {
+		yaffsfs_SetError(-EFAULT);
+		return -1;
+	}
+
+	yaffsfs_Lock();
+
+	obj = yaffsfs_FindObject(NULL, path, 0, 1, &dir, &notDir, &loop);
+
+	if (!dir && notDir)
+		yaffsfs_SetError(-ENOTDIR);
+	else if (loop)
+		yaffsfs_SetError(-ELOOP);
+	else if (!dir || !obj)
+		yaffsfs_SetError(-ENOENT);
+	else if (obj->variant_type != YAFFS_OBJECT_TYPE_SYMLINK)
+		yaffsfs_SetError(-EINVAL);
+	else {
+		YCHAR *alias = obj->variant.symlink_variant.alias;
+		memset(buf, 0, bufsiz);
+		yaffs_strncpy(buf, alias, bufsiz - 1);
+		retVal = 0;
+	}
+	yaffsfs_Unlock();
+	return retVal;
+}
+
+int yaffs_link(const YCHAR *oldpath, const YCHAR *linkpath)
+{
+	/* Creates a link called newpath to existing oldpath */
+	struct yaffs_obj *obj = NULL;
+	struct yaffs_obj *lnk = NULL;
+	struct yaffs_obj *obj_dir = NULL;
+	struct yaffs_obj *lnk_dir = NULL;
+	int retVal = -1;
+	int notDirObj = 0;
+	int notDirLnk = 0;
+	int objLoop = 0;
+	int lnkLoop = 0;
+	YCHAR *newname;
+
+	if (!oldpath || !linkpath) {
+		yaffsfs_SetError(-EFAULT);
+		return -1;
+	}
+
+	if (yaffsfs_CheckPath(linkpath) < 0 || yaffsfs_CheckPath(oldpath) < 0) {
+		yaffsfs_SetError(-ENAMETOOLONG);
+		return -1;
+	}
+
+	yaffsfs_Lock();
+
+	obj = yaffsfs_FindObject(NULL, oldpath, 0, 1,
+				 &obj_dir, &notDirObj, &objLoop);
+	lnk = yaffsfs_FindObject(NULL, linkpath, 0, 0, NULL, NULL, NULL);
+	lnk_dir = yaffsfs_FindDirectory(NULL, linkpath, &newname,
+					0, &notDirLnk, &lnkLoop);
+
+	if ((!obj_dir && notDirObj) || (!lnk_dir && notDirLnk))
+		yaffsfs_SetError(-ENOTDIR);
+	else if (objLoop || lnkLoop)
+		yaffsfs_SetError(-ELOOP);
+	else if (!obj_dir || !lnk_dir || !obj)
+		yaffsfs_SetError(-ENOENT);
+	else if (obj->my_dev->read_only)
+		yaffsfs_SetError(-EROFS);
+	else if (yaffsfs_TooManyObjects(obj->my_dev))
+		yaffsfs_SetError(-ENFILE);
+	else if (lnk)
+		yaffsfs_SetError(-EEXIST);
+	else if (lnk_dir->my_dev != obj->my_dev)
+		yaffsfs_SetError(-EXDEV);
+	else {
+		retVal = yaffsfs_CheckNameLength(newname);
+
+		if (retVal == 0) {
+			lnk = yaffs_link_obj(lnk_dir, newname, obj);
+			if (lnk)
+				retVal = 0;
+			else {
+				yaffsfs_SetError(-ENOSPC);
+				retVal = -1;
+			}
+		}
+	}
+	yaffsfs_Unlock();
+
+	return retVal;
+}
+
+int yaffs_mknod(const YCHAR *pathname, mode_t mode, dev_t dev)
+{
+	(void) pathname;
+	(void) mode;
+	(void) dev;
+
+	yaffsfs_SetError(-EINVAL);
+	return -1;
+}
+
+/*
+ * D E B U G   F U N C T I O N S
+ */
+
+/*
+ * yaffs_n_handles()
+ * Returns number of handles attached to the object
+ */
+int yaffs_n_handles(const YCHAR *path)
+{
+	struct yaffs_obj *obj;
+
+	if (!path) {
+		yaffsfs_SetError(-EFAULT);
+		return -1;
+	}
+
+	if (yaffsfs_CheckPath(path) < 0) {
+		yaffsfs_SetError(-ENAMETOOLONG);
+		return -1;
+	}
+
+	obj = yaffsfs_FindObject(NULL, path, 0, 1, NULL, NULL, NULL);
+
+	if (obj)
+		return yaffsfs_CountHandles(obj);
+	else
+		return -1;
+}
+
+int yaffs_get_error(void)
+{
+	return yaffsfs_GetLastError();
+}
+
+int yaffs_set_error(int error)
+{
+	yaffsfs_SetError(error);
+	return 0;
+}
+
+int yaffs_dump_dev(const YCHAR *path)
+{
+#if 1
+	(void) path;
+#else
+	YCHAR *rest;
+
+	struct yaffs_obj *obj = yaffsfs_FindRoot(path, &rest);
+
+	if (obj) {
+		struct yaffs_dev *dev = obj->my_dev;
+
+		printf("\n"
+		       "n_page_writes.......... %d\n"
+		       "n_page_reads........... %d\n"
+		       "n_erasures....... %d\n"
+		       "n_gc_copies............ %d\n"
+		       "garbageCollections... %d\n"
+		       "passiveGarbageColl'ns %d\n"
+		       "\n",
+		       dev->n_page_writes,
+		       dev->n_page_reads,
+		       dev->n_erasures,
+		       dev->n_gc_copies,
+		       dev->garbageCollections, dev->passiveGarbageCollections);
+
+	}
+#endif
+	return 0;
+}
diff --git a/linux-bsp/asm-study/yaffs2/yaffs2/yaffsfs.h b/linux-bsp/asm-study/yaffs2/yaffs2/yaffsfs.h
new file mode 100644
index 0000000..334bb19
--- /dev/null
+++ b/linux-bsp/asm-study/yaffs2/yaffs2/yaffsfs.h
@@ -0,0 +1,233 @@
+/*
+ * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
+ *
+ * Copyright (C) 2002-2011 Aleph One Ltd.
+ *   for Toby Churchill Ltd and Brightstar Engineering
+ *
+ * Created by Charles Manning <charles@aleph1.co.uk>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 2.1 as
+ * published by the Free Software Foundation.
+ *
+ * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
+ */
+
+/*
+ * Header file for using yaffs in an application via
+ * a direct interface.
+ */
+
+
+#ifndef __YAFFSFS_H__
+#define __YAFFSFS_H__
+
+#include "yaffscfg.h"
+#include "yportenv.h"
+
+
+#ifndef NAME_MAX
+#define NAME_MAX	256
+#endif
+
+#define YAFFS_MAX_FILE_SIZE \
+	( (sizeof(Y_LOFF_T) < 8) ? YAFFS_MAX_FILE_SIZE_32 : (0x800000000LL - 1) )
+
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+
+struct yaffs_dirent {
+	long d_ino;			/* inode number */
+	off_t d_off;			/* offset to this dirent */
+	unsigned short d_reclen;	/* length of this dirent */
+	YUCHAR d_type;			/* type of this record */
+	YCHAR d_name[NAME_MAX+1];	/* file name (null-terminated) */
+	unsigned d_dont_use;		/* debug: not for public consumption */
+};
+
+typedef struct opaque_structure yaffs_DIR;
+
+
+
+struct yaffs_stat {
+	int		st_dev;		/* device */
+	int		st_ino;		/* inode */
+	unsigned	st_mode;	/* protection */
+	int		st_nlink;	/* number of hard links */
+	int		st_uid;		/* user ID of owner */
+	int		st_gid;		/* group ID of owner */
+	unsigned	st_rdev;	/* device type (if inode device) */
+	Y_LOFF_T		st_size;	/* total size, in bytes */
+	unsigned long	st_blksize;	/* blocksize for filesystem I/O */
+	unsigned long	st_blocks;	/* number of blocks allocated */
+#ifdef CONFIG_YAFFS_WINCE
+	/* Special 64-bit times for WinCE */
+	unsigned long	yst_wince_atime[2];
+	unsigned long	yst_wince_mtime[2];
+	unsigned long	yst_wince_ctime[2];
+#else
+	unsigned long	yst_atime;	/* time of last access */
+	unsigned long	yst_mtime;	/* time of last modification */
+	unsigned long	yst_ctime;	/* time of last change */
+#endif
+};
+
+
+struct yaffs_utimbuf {
+	unsigned long actime;
+	unsigned long modtime;
+};
+
+
+int yaffs_open(const YCHAR *path, int oflag, int mode) ;
+
+int yaffs_close(int fd) ;
+int yaffs_fsync(int fd) ;
+int yaffs_fdatasync(int fd) ;
+int yaffs_flush(int fd) ; /* same as yaffs_fsync() */
+
+int yaffs_access(const YCHAR *path, int amode);
+
+int yaffs_dup(int fd);
+
+int yaffs_read(int fd, void *buf, unsigned int nbyte) ;
+int yaffs_write(int fd, const void *buf, unsigned int nbyte) ;
+
+int yaffs_pread(int fd, void *buf, unsigned int nbyte, Y_LOFF_T offset);
+int yaffs_pwrite(int fd, const void *buf, unsigned int nbyte, Y_LOFF_T offset);
+
+Y_LOFF_T yaffs_lseek(int fd, Y_LOFF_T offset, int whence) ;
+
+int yaffs_truncate(const YCHAR *path, Y_LOFF_T new_size);
+int yaffs_ftruncate(int fd, Y_LOFF_T new_size);
+
+int yaffs_unlink(const YCHAR *path) ;
+int yaffs_rm(const YCHAR *path, int recursive); /* Add by guowenxue, 2013.05.30 */
+int yaffs_ls(const char *dname, int recursive); /* Add by guowenxue, 2013.05.30 */
+int yaffs_rename(const YCHAR *oldPath, const YCHAR *newPath) ;
+
+int yaffs_stat(const YCHAR *path, struct yaffs_stat *buf) ;
+int yaffs_lstat(const YCHAR *path, struct yaffs_stat *buf) ;
+int yaffs_fstat(int fd, struct yaffs_stat *buf) ;
+
+int yaffs_utime(const YCHAR *path, const struct yaffs_utimbuf *buf);
+int yaffs_futime(int fd, const struct yaffs_utimbuf *buf);
+
+
+int yaffs_setxattr(const char *path, const char *name,
+			const void *data, int size, int flags);
+int yaffs_lsetxattr(const char *path, const char *name,
+			const void *data, int size, int flags);
+int yaffs_fsetxattr(int fd, const char *name,
+			const void *data, int size, int flags);
+
+int yaffs_getxattr(const char *path, const char *name,
+			void *data, int size);
+int yaffs_lgetxattr(const char *path, const char *name,
+			void *data, int size);
+int yaffs_fgetxattr(int fd, const char *name,
+			void *data, int size);
+
+int yaffs_removexattr(const char *path, const char *name);
+int yaffs_lremovexattr(const char *path, const char *name);
+int yaffs_fremovexattr(int fd, const char *name);
+
+int yaffs_listxattr(const char *path, char *list, int size);
+int yaffs_llistxattr(const char *path, char *list, int size);
+int yaffs_flistxattr(int fd, char *list, int size);
+
+
+#ifdef CONFIG_YAFFS_WINCE
+
+int yaffs_set_wince_times(int fd,
+			const unsigned *wctime,
+			const unsigned *watime,
+			const unsigned *wmtime);
+int yaffs_get_wince_times(int fd,
+			unsigned *wctime,
+			unsigned *watime,
+			unsigned *wmtime);
+
+#endif
+
+int yaffs_chmod(const YCHAR *path, mode_t mode);
+int yaffs_fchmod(int fd, mode_t mode);
+
+int yaffs_mkdir(const YCHAR *path, mode_t mode) ;
+int yaffs_rmdir(const YCHAR *path) ;
+
+yaffs_DIR *yaffs_opendir(const YCHAR *dirname) ;
+struct yaffs_dirent *yaffs_readdir(yaffs_DIR *dirp) ;
+void yaffs_rewinddir(yaffs_DIR *dirp) ;
+int yaffs_closedir(yaffs_DIR *dirp) ;
+
+int yaffs_mount(const YCHAR *path) ;
+int yaffs_mount2(const YCHAR *path, int read_only);
+int yaffs_mount_common(const YCHAR *path, int read_only, int skip_checkpt);
+
+int yaffs_unmount(const YCHAR *path) ;
+int yaffs_unmount2(const YCHAR *path, int force);
+int yaffs_remount(const YCHAR *path, int force, int read_only);
+
+int yaffs_format(const YCHAR *path,
+		int unmount_flag,
+		int force_unmount_flag,
+		int remount_flag);
+
+int yaffs_sync(const YCHAR *path) ;
+
+int yaffs_symlink(const YCHAR *oldpath, const YCHAR *newpath);
+int yaffs_readlink(const YCHAR *path, YCHAR *buf, int bufsiz);
+
+int yaffs_link(const YCHAR *oldpath, const YCHAR *newpath);
+int yaffs_mknod(const YCHAR *pathname, mode_t mode, dev_t dev);
+
+Y_LOFF_T yaffs_freespace(const YCHAR *path);
+Y_LOFF_T yaffs_totalspace(const YCHAR *path);
+
+int yaffs_inodecount(const YCHAR *path);
+
+int yaffs_n_handles(const YCHAR *path);
+
+#define YAFFS_SHARE_READ  1
+#define YAFFS_SHARE_WRITE 2
+int yaffs_open_sharing(const YCHAR *path, int oflag, int mode, int shareMode);
+
+struct yaffs_dev;
+void yaffs_add_device(struct yaffs_dev *dev);
+
+int yaffs_start_up(void);
+int yaffsfs_GetLastError(void);
+
+/* Functions to iterate through devices. NB Use with extreme care! */
+void yaffs_dev_rewind(void);
+struct yaffs_dev *yaffs_next_dev(void);
+
+/* Function to get the last error */
+int yaffs_get_error(void);
+const char *yaffs_error_to_str(int err);
+static inline const char *yaffs_perror(void) /* Add by guowenxue, 2013.05.30  */
+{
+    return yaffs_error_to_str(yaffs_get_error());
+}
+
+/* Function only for debugging */
+void *yaffs_getdev(const YCHAR *path);
+int yaffs_dump_dev(const YCHAR *path);
+int yaffs_set_error(int error);
+
+/* Trace control functions */
+unsigned  yaffs_set_trace(unsigned tm);
+unsigned  yaffs_get_trace(void);
+
+
+#ifdef __cplusplus
+}
+#endif
+
+
+#endif
diff --git a/linux-bsp/asm-study/yaffs2/yaffs2/ydirectenv.h b/linux-bsp/asm-study/yaffs2/yaffs2/ydirectenv.h
new file mode 100644
index 0000000..26efd7c
--- /dev/null
+++ b/linux-bsp/asm-study/yaffs2/yaffs2/ydirectenv.h
@@ -0,0 +1,99 @@
+/*
+ * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
+ *
+ * Copyright (C) 2002-2011 Aleph One Ltd.
+ *   for Toby Churchill Ltd and Brightstar Engineering
+ *
+ * Created by Charles Manning <charles@aleph1.co.uk>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 2.1 as
+ * published by the Free Software Foundation.
+ *
+ * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
+ */
+
+/*
+ * ydirectenv.h: Environment wrappers for YAFFS direct.
+ */
+
+#ifndef __YDIRECTENV_H__
+#define __YDIRECTENV_H__
+
+#include "stdio.h"
+#include "string.h"
+#include "yaffs_osglue.h"
+#include "yaffs_hweight.h"
+
+void yaffs_bug_fn(const char *file_name, int line_no);
+
+#define BUG() do { yaffs_bug_fn(__FILE__, __LINE__); } while (0)
+
+
+#define YCHAR char
+#define YUCHAR unsigned char
+#define _Y(x) x
+
+#ifndef Y_LOFF_T
+#define Y_LOFF_T loff_t
+#endif
+
+#define yaffs_strcat(a, b)	strcat(a, b)
+#define yaffs_strcpy(a, b)	strcpy(a, b)
+#define yaffs_strncpy(a, b, c)	strncpy(a, b, c)
+#define yaffs_strnlen(s, m)	strnlen(s, m)
+#ifdef CONFIG_YAFFS_CASE_INSENSITIVE
+#define yaffs_strcmp(a, b)	strcasecmp(a, b)
+#define yaffs_strncmp(a, b, c)	strncasecmp(a, b, c)
+#else
+#define yaffs_strcmp(a, b)	strcmp(a, b)
+#define yaffs_strncmp(a, b, c)	strncmp(a, b, c)
+#endif
+
+#define hweight8(x)	yaffs_hweight8(x)
+#define hweight32(x)	yaffs_hweight32(x)
+
+void yaffs_qsort(void *aa, size_t n, size_t es,
+		int (*cmp)(const void *, const void *));
+
+#define sort(base, n, sz, cmp_fn, swp) yaffs_qsort(base, n, sz, cmp_fn)
+
+#define YAFFS_PATH_DIVIDERS  "/"
+
+#ifdef NO_inline
+#define inline
+#else
+#define inline __inline__
+#endif
+
+#define kmalloc(x, flags) yaffsfs_malloc(x)
+#define kfree(x)   yaffsfs_free(x)
+#define vmalloc(x) yaffsfs_malloc(x)
+#define vfree(x) yaffsfs_free(x)
+
+#define cond_resched()  do {} while (0)
+
+#define yaffs_trace(msk, fmt, ...) do { \
+	if (yaffs_trace_mask & (msk)) \
+		printf("yaffs: " fmt "\n", ##__VA_ARGS__); \
+} while (0)
+
+
+#define YAFFS_LOSTNFOUND_NAME		"lost+found"
+#define YAFFS_LOSTNFOUND_PREFIX		"obj"
+
+#include "yaffscfg.h"
+
+#define Y_CURRENT_TIME yaffsfs_CurrentTime()
+#define Y_TIME_CONVERT(x) x
+
+#define YAFFS_ROOT_MODE			0666
+#define YAFFS_LOSTNFOUND_MODE		0666
+
+#include "yaffs_list.h"
+
+#include "yaffsfs.h"
+
+#endif
+
+
diff --git a/linux-bsp/asm-study/yaffs2/yaffs2/yportenv.h b/linux-bsp/asm-study/yaffs2/yaffs2/yportenv.h
new file mode 100644
index 0000000..194e0c8
--- /dev/null
+++ b/linux-bsp/asm-study/yaffs2/yaffs2/yportenv.h
@@ -0,0 +1,318 @@
+/*
+ * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
+ *
+ * Copyright (C) 2002-2011 Aleph One Ltd.
+ *   for Toby Churchill Ltd and Brightstar Engineering
+ *
+ * Created by Charles Manning <charles@aleph1.co.uk>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 2.1 as
+ * published by the Free Software Foundation.
+ *
+ * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
+ */
+
+
+#ifndef __YPORTENV_H__
+#define __YPORTENV_H__
+
+#include <stdio.h>
+#include <string.h>
+#include <types.h>
+#include <malloc.h>
+
+#define CONFIG_YAFFS_DIRECT             1 /* Add by guowenxue  */
+//#define CONFIG_YAFFS_DEFINES_TYPES      1
+#define CONFIG_YAFFS_PROVIDE_DEFS       1
+#define CONFIG_YAFFSFS_PROVIDE_VALUES   1
+
+
+/* Definition of types */
+#ifdef CONFIG_YAFFS_DEFINES_TYPES
+typedef unsigned char u8;
+typedef unsigned short u16;
+typedef unsigned int u32;
+#endif
+
+
+#ifdef CONFIG_YAFFS_PROVIDE_DEFS
+/* File types */
+
+
+#define DT_UNKNOWN	0
+#define DT_FIFO		1
+#define DT_CHR		2
+#define DT_DIR		4
+#define DT_BLK		6
+#define DT_REG		8
+#define DT_LNK		10
+#define DT_SOCK		12
+#define DT_WHT		14
+
+
+/*
+ * Attribute flags.
+ * These are or-ed together to select what has been changed.
+ */
+#define ATTR_MODE	1
+#define ATTR_UID	2
+#define ATTR_GID	4
+#define ATTR_SIZE	8
+#define ATTR_ATIME	16
+#define ATTR_MTIME	32
+#define ATTR_CTIME	64
+
+struct iattr {
+	unsigned int ia_valid;
+	unsigned ia_mode;
+	unsigned ia_uid;
+	unsigned ia_gid;
+	unsigned ia_size;
+	unsigned ia_atime;
+	unsigned ia_mtime;
+	unsigned ia_ctime;
+	unsigned int ia_attr_flags;
+};
+
+#endif
+
+
+
+#if defined CONFIG_YAFFS_WINCE
+
+#include "ywinceenv.h"
+
+
+#elif defined CONFIG_YAFFS_DIRECT
+
+/* Direct interface */
+#include "ydirectenv.h"
+
+#elif defined CONFIG_YAFFS_UTIL
+
+#include "yutilsenv.h"
+
+#else
+/* Should have specified a configuration type */
+#error Unknown configuration
+
+#endif
+
+#if defined(CONFIG_YAFFS_DIRECT) || defined(CONFIG_YAFFS_WINCE)
+
+#ifdef CONFIG_YAFFSFS_PROVIDE_VALUES
+
+#ifndef O_RDONLY
+#define O_RDONLY	00
+#endif
+
+#ifndef O_WRONLY
+#define O_WRONLY	01
+#endif
+
+#ifndef O_RDWR
+#define O_RDWR		02
+#endif
+
+#ifndef O_CREAT
+#define O_CREAT		0100
+#endif
+
+#ifndef O_EXCL
+#define O_EXCL		0200
+#endif
+
+#ifndef O_TRUNC
+#define O_TRUNC		01000
+#endif
+
+#ifndef O_APPEND
+#define O_APPEND	02000
+#endif
+
+#ifndef SEEK_SET
+#define SEEK_SET	0
+#endif
+
+#ifndef SEEK_CUR
+#define SEEK_CUR	1
+#endif
+
+#ifndef SEEK_END
+#define SEEK_END	2
+#endif
+
+#ifndef EBUSY
+#define EBUSY	16
+#endif
+
+#ifndef ENODEV
+#define ENODEV	19
+#endif
+
+#ifndef EINVAL
+#define EINVAL	22
+#endif
+
+#ifndef ENFILE
+#define ENFILE	23
+#endif
+
+#ifndef EBADF
+#define EBADF	9
+#endif
+
+#ifndef EACCES
+#define EACCES	13
+#endif
+
+#ifndef EXDEV
+#define EXDEV	18
+#endif
+
+#ifndef ENOENT
+#define ENOENT	2
+#endif
+
+#ifndef ENOSPC
+#define ENOSPC	28
+#endif
+
+#ifndef EROFS
+#define EROFS	30
+#endif
+
+#ifndef ERANGE
+#define ERANGE 34
+#endif
+
+#ifndef ENODATA
+#define ENODATA 61
+#endif
+
+#ifndef ENOTEMPTY
+#define ENOTEMPTY 39
+#endif
+
+#ifndef ENAMETOOLONG
+#define ENAMETOOLONG 36
+#endif
+
+#ifndef ENOMEM
+#define ENOMEM 12
+#endif
+
+#ifndef EFAULT
+#define EFAULT 14
+#endif
+
+#ifndef EEXIST
+#define EEXIST 17
+#endif
+
+#ifndef ENOTDIR
+#define ENOTDIR 20
+#endif
+
+#ifndef EISDIR
+#define EISDIR 21
+#endif
+
+#ifndef ELOOP
+#define ELOOP	40
+#endif
+
+
+/* Mode flags */
+
+#ifndef S_IFMT
+#define S_IFMT		0170000
+#endif
+
+#ifndef S_IFSOCK
+#define S_IFSOCK	0140000
+#endif
+
+#ifndef S_IFIFO
+#define S_IFIFO		0010000
+#endif
+
+#ifndef S_IFCHR
+#define S_IFCHR		0020000
+#endif
+
+#ifndef S_IFBLK
+#define S_IFBLK		0060000
+#endif
+
+#ifndef S_IFLNK
+#define S_IFLNK		0120000
+#endif
+
+#ifndef S_IFDIR
+#define S_IFDIR		0040000
+#endif
+
+#ifndef S_IFREG
+#define S_IFREG		0100000
+#endif
+
+#define S_ISSOCK(m)	(((m) & S_IFMT) == S_IFSOCK)
+#define S_ISLNK(m)	(((m) & S_IFMT) == S_IFLNK)
+#define S_ISDIR(m)	(((m) & S_IFMT) == S_IFDIR)
+#define S_ISREG(m)	(((m) & S_IFMT) == S_IFREG)
+#define S_ISBLK(m)	(((m) & S_IFMT) == S_IFBLK)
+#define S_ISCHR(m)	(((m) & S_IFMT) == S_IFCHR)
+#define S_ISFIFO(m)	(((m) & S_IFMT) == S_IFIFO)
+
+
+#ifndef S_IREAD
+#define S_IREAD		0000400
+#endif
+
+#ifndef S_IWRITE
+#define	S_IWRITE	0000200
+#endif
+
+#ifndef S_IEXEC
+#define	S_IEXEC	0000100
+#endif
+
+#ifndef XATTR_CREATE
+#define XATTR_CREATE 1
+#endif
+
+#ifndef XATTR_REPLACE
+#define XATTR_REPLACE 2
+#endif
+
+#ifndef R_OK
+#define R_OK	4
+#define W_OK	2
+#define X_OK	1
+#define F_OK	0
+#endif
+
+#else
+#include <errno.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#endif
+
+#endif
+
+#ifndef Y_DUMP_STACK
+#define Y_DUMP_STACK() do { } while (0)
+#endif
+
+#ifndef BUG
+#define BUG() do {\
+	yaffs_trace(YAFFS_TRACE_BUG,\
+		"==>> yaffs bug: " __FILE__ " %d",\
+		__LINE__);\
+	Y_DUMP_STACK();\
+} while (0)
+#endif
+
+#endif
diff --git a/linux-bsp/bootstrap/bootstrap.S b/linux-bsp/bootstrap/bootstrap.S
new file mode 100644
index 0000000..530fd1c
--- /dev/null
+++ b/linux-bsp/bootstrap/bootstrap.S
@@ -0,0 +1,156 @@
+
+/********************************************************************************************
+ *        File:  bootstrap.S 
+ *     Version:  1.0.0
+ *   Copyright:  2011 (c) Guo Wenxue <Email: guowenxue@gmail.com QQ:281143292>
+ * Description:  If we wanna debug u-boot by J-Link in external SDRAM, we must download this 
+ *               bootstrap.bin file into s3c24x0 8K internal SRAM(Stepping Stone) and excute 
+ *               first, which used to initialize the CPU and external SDRAM. Only after init 
+ *               the SDRAM then we can debug u-boot in it.
+ *   ChangeLog:  1, Release initial version on "Tue Jul 12 16:43:18 CST 2011"
+ *
+ *******************************************************************************************/
+
+#include "bootstrap.h"
+
+    .text
+    .align 2
+    .global _start
+
+_start:
+    /* set cpu to SVC32 mode */
+    mrs r0, cpsr
+    bic r0, r0, #0x1f
+    orr r0, r0, #0xd3
+    msr cpsr, r0
+
+    /* Disable watchdog */
+    ldr r0, =S3C_WATCHDOG_BASE
+    mov r1, #0
+    str r1, [r0]
+
+    /* Disable Interrupt */
+    ldr r0, =S3C_INTERRUPT_BASE
+    mov r1, #0xffffffff
+    str r1, [r0, #INTMSK_OFFSET]
+    ldr r1, =0x000007ff
+    str r1, [r0, #INTSUBMSK_OFFSET]
+
+    /* http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.ddi0290g/Babjcgjg.html */
+    mov r0, #0
+    mcr p15, 0, r0, c7, c7, 0	/* flush v3/v4 cache, Invalidate ICache and DCache */
+    mcr p15, 0, r0, c8, c7, 0	/* flush v4 TLB */
+
+    /* disable MMU stuff and caches */
+    mrc p15, 0, r0, c1, c0, 0
+    bic r0, r0, #0x00002300	@ clear bits 13, 9:8 (--V- --RS)
+    bic r0, r0, #0x00000087	@ clear bits 7, 2:0 (B--- -CAM) 
+    orr r0, r0, #0x00000002	@ set bit 2 (A) Align
+    orr r0, r0, #0x00001000	@ set bit 12 (I) I-Cache
+    mcr p15, 0, r0, c1, c0, 0
+
+
+ /*******************************************************************************************
+  * Init system clock and power, FCLK:HCLK:PCLK = 1:4:8 
+  * Reference to S3C2440 datasheet: Chap 7 Clock&Power Management
+  *
+  * Initialize System Clock FCLK=400MHz HCLK=100MHz PCLK=50MHz
+  * FCLK is used by ARM920T
+  * HCLK is used for AHB bus, which is used by the ARM920T, the memory controller,
+  *      the interrupt controller, the LCD controller, the DMA and USB host block.
+  * PCLK is is used for APB bus,which is used by the peripherals such as WDT,IIS,I2C,
+  *      PWM timer,MMC interface,ADC,UART,GPIO,RTC and SPI.
+  ******************************************************************************************/
+
+    /*Set LOCKTIME as default value 0x00ffffff*/
+    ldr r0, =S3C_CLOCK_POWER_BASE
+    ldr r1, =0x00ffffff
+    str r1, [r0, #LOCKTIME_OFFSET] 
+
+ /*******************************************************************************************
+  * Reference to S3C2440 datasheet: Chap 7-8 ~ Page 242
+  *
+  * Set the selection of Dividing Ratio between FCLK,HCLK and PCLK as FCLK:HCLK:PCLK = 1:4:8.
+  * This ratio is determined by HDIVN(here is 2) and PDIVN(here is 1) control register.
+  * Refer to the s3c2440 datasheet
+  *******************************************************************************************/
+    ldr r0, =S3C_CLOCK_POWER_BASE
+    mov r1, #5
+    str r1, [r0, #CLKDIVN_OFFSET]  /*Set Clock Divider*/
+
+    mrc p15, 0, r1, c1, c0, 0 
+    orr r1, r1, #0xc0000000
+    mcr p15, 0, r1, c1, c0, 0 
+
+ /***************************************************************************************
+  *  Reference to S3C2440 datasheet: Chap 7-20 ~ Page 254
+  *
+  *  Set MPLLCON(0x4C000004) register as:
+  *    [19:12]:  MDIV(Main Divider control)=0x7F (value set in MDIV_405)
+  *      [9:4]:  PDIV(Pre-devider control)=0x02  (value set in PSDIV_405)
+  *      [1:0]:  SDIV(Post divider control)=0x01 (value set in PSDIV_405)
+  *
+  *  MPLL(FCLK) = (2 * m * Fin)/(p * 2^s)
+  *  m=(MDIV+8), p=(PDIV+2), s=SDIV
+  *
+  *  So FCLK=((2*(127+8)*Fin)) / ((2+2)*2^1)
+  *         = (2*135*12MHz)/8
+  *         = 405MHz
+  *  For FCLK:HCLK:PCLK=1:4:8, so HCLK=100MHz, PCLK=50MHz
+  ***************************************************************************************/
+    mov r1, #S3C_CLOCK_POWER_BASE
+    mov r2, #MDIV_405
+    add r2, r2, #PSDIV_405
+    str r2, [r1, #MPLLCON_OFFSET]
+
+mem_init:
+    /* memory control configuration */
+    /* make r0 relative the current location so that it */
+    /* reads SMRDATA out of FLASH rather than memory ! */
+    ldr r0, =SMRDATA
+    ldr r1, =mem_init
+    sub r0, r0, r1
+    adr r3, mem_init       /* r3 <- current position of code   */
+    add r0, r0, r3  /*r0 =SMRDATA-mem_init+mem_init =SMRDATA*/
+    ldr r1, =BWSCON /* Bus Width Status Controller */
+    add r2, r0, #13*4
+0:
+    ldr r3, [r0], #4
+    str r3, [r1], #4
+    cmp r2, r0
+    bne 0b
+
+    /*Set GPIO5, GPIO6, GPIO8, GPIO10 as GPIO OUTPUT mode*/ 
+    ldr     r0, =GPBCON
+    ldr     r1, [r0]
+    bic     r1, r1, #0xC00       /*Set GPBCON for GPIO5 as 0x00 */
+    orr     r1, r1, #0x0400      /*Set GPBCON for GPIO5 as GPIOOUT, 0x01*/
+    str     r1, [r0]
+
+    ldr     r3, [r2]
+    bic     r3, r3, #(1<<LED0)  /*Clear bit 5, set GPB5 as low level*/
+    str     r3, [r2]
+
+
+    /* everything is fine now */
+dead_loop:
+    b   dead_loop
+
+    .ltorg
+/* the literal pools origin */
+
+SMRDATA:
+    .word (0+(B1_BWSCON<<4)+(B2_BWSCON<<8)+(B3_BWSCON<<12)+(B4_BWSCON<<16)+(B5_BWSCON<<20)+(B6_BWSCON<<24)+(B7_BWSCON<<28))
+    .word ((B0_Tacs<<13)+(B0_Tcos<<11)+(B0_Tacc<<8)+(B0_Tcoh<<6)+(B0_Tah<<4)+(B0_Tacp<<2)+(B0_PMC))
+    .word ((B1_Tacs<<13)+(B1_Tcos<<11)+(B1_Tacc<<8)+(B1_Tcoh<<6)+(B1_Tah<<4)+(B1_Tacp<<2)+(B1_PMC))
+    .word ((B2_Tacs<<13)+(B2_Tcos<<11)+(B2_Tacc<<8)+(B2_Tcoh<<6)+(B2_Tah<<4)+(B2_Tacp<<2)+(B2_PMC))
+    .word ((B3_Tacs<<13)+(B3_Tcos<<11)+(B3_Tacc<<8)+(B3_Tcoh<<6)+(B3_Tah<<4)+(B3_Tacp<<2)+(B3_PMC))
+    .word ((B4_Tacs<<13)+(B4_Tcos<<11)+(B4_Tacc<<8)+(B4_Tcoh<<6)+(B4_Tah<<4)+(B4_Tacp<<2)+(B4_PMC))
+    .word ((B5_Tacs<<13)+(B5_Tcos<<11)+(B5_Tacc<<8)+(B5_Tcoh<<6)+(B5_Tah<<4)+(B5_Tacp<<2)+(B5_PMC))
+    .word ((B6_MT<<15)+(B6_Trcd<<2)+(B6_SCAN))
+    .word ((B7_MT<<15)+(B7_Trcd<<2)+(B7_SCAN))
+    .word ((REFEN<<23)+(TREFMD<<22)+(Trp<<20)+(Tsrc<<18)+REFCNT)
+    .word 0xb2
+    .word 0x30
+    .word 0x30
+
diff --git a/linux-bsp/bootstrap/bootstrap.h b/linux-bsp/bootstrap/bootstrap.h
new file mode 100644
index 0000000..1e85138
--- /dev/null
+++ b/linux-bsp/bootstrap/bootstrap.h
@@ -0,0 +1,148 @@
+/*
+ * =====================================================================================
+ *
+ *       Filename:  bootstrap.h
+ *        Version:  1.0.0
+ *         Author:  Guo Wenxue<Email: guowenxue@ghlsystems.com QQ:281143292>
+ *      CopyRight:  2011 (C) Guo Wenxue
+ *    Description:  Some Reigster address definition for bootstrap.S
+ * =====================================================================================
+ */
+
+#define S3C_WATCHDOG_BASE       0x53000000
+
+#define S3C_INTERRUPT_BASE      0x4a000000
+#define SRCPND_OFFSET           0x00
+#define INTMOD_OFFSET           0x04
+#define INTMSK_OFFSET           0x08
+#define PRIORITY_OFFSET         0x0c
+#define INTPND_OFFSET           0x10
+#define INTOFFSET_OFFSET        0x14
+#define SUBSRCPND_OFFSET        0x18
+#define INTSUBMSK_OFFSET        0x1c
+
+#define S3C_CLOCK_POWER_BASE    0x4c000000
+#define LOCKTIME_OFFSET         0x00
+#define MPLLCON_OFFSET          0x04
+#define UPLLCON_OFFSET          0x08
+#define CLKCON_OFFSET           0x0c
+#define CLKSLOW_OFFSET          0x10
+#define CLKDIVN_OFFSET          0x14
+#define CAMDIVN_OFFSET          0x18
+
+#define BWSCON  		        0x48000000
+
+#define MDIV_405                0x7f << 12
+#define PSDIV_405               0x21
+
+
+#define GPBCON   0x56000010
+#define GPBDAT   0x56000014
+#define GPBUP    0x56000018
+
+#define OUTPUT   0x01   /* Set GPIO port as output mode*/
+#define INPUT    0x00   /* Set GPIO port as input mode*/
+
+#define BEEP     0      /* On FL2440 board, LED0 use GPB0*/
+#define LED0     5      /* On FL2440 board, LED0 use GPB5*/
+#define LED1     6      /* On FL2440 board, LED0 use GPB6*/
+#define LED2     8      /* On FL2440 board, LED0 use GPB8*/
+#define LED3     10     /* On FL2440 board, LED0 use GPB10*/
+
+/*  BWSCON */
+#define DW8             (0x0)
+#define DW16            (0x1)
+#define DW32            (0x2)
+#define WAIT            (0x1<<2)
+#define UBLB            (0x1<<3)
+
+#define B1_BWSCON       (DW16)
+#define B2_BWSCON       (DW16)
+#define B3_BWSCON       (DW16 + WAIT + UBLB)
+#define B4_BWSCON       (DW16)
+#define B5_BWSCON       (DW16)
+#define B6_BWSCON       (DW32)
+#define B7_BWSCON       (DW32)
+
+#define B0_Tacs         0x0
+#define B0_Tcos         0x0
+#define B0_Tacc         0x7
+#define B0_Tcoh         0x0
+#define B0_Tah          0x0
+#define B0_Tacp         0x0
+#define B0_PMC          0x0
+
+#define B1_Tacs         0x0
+#define B1_Tcos         0x0
+#define B1_Tacc         0x7
+#define B1_Tcoh         0x0
+#define B1_Tah          0x0
+#define B1_Tacp         0x0
+#define B1_PMC          0x0 
+
+#define B2_Tacs         0x0
+#define B2_Tcos         0x0
+#define B2_Tacc         0x7
+#define B2_Tcoh         0x0
+#define B2_Tah          0x0
+#define B2_Tacp         0x0
+#define B2_PMC          0x0
+
+#define B3_Tacs         0xc
+#define B3_Tcos         0x7
+#define B3_Tacc         0xf
+#define B3_Tcoh         0x1
+#define B3_Tah          0x0
+#define B3_Tacp         0x0
+#define B3_PMC          0x0
+
+#define B4_Tacs         0x0
+#define B4_Tcos         0x0
+#define B4_Tacc         0x7
+#define B4_Tcoh         0x0
+#define B4_Tah          0x0
+#define B4_Tacp         0x0
+#define B4_PMC          0x0
+
+#define B5_Tacs         0xc
+#define B5_Tcos         0x7
+#define B5_Tacc         0xf
+#define B5_Tcoh         0x1
+#define B5_Tah          0x0
+#define B5_Tacp         0x0
+#define B5_PMC          0x0
+
+/* SDRAM is on HSB bus, so its clock is from HCLK, FCLK=400, HCLK=100; so SDRAM 1clk=10ns */ 
+
+#define B6_MT           0x3 /*  SDRAM */
+// K4S561632 datasheet: RAS to CAS delay(Trcd) Min value should be 18/20ns, HCLK is 100MHz, so 1clk=10ns
+// EM63A165  datasheet: RAS# to CAS# delay(Trcd) Min value should be 15/20ns, HCLK is 100MHz, so 1clk=10ns
+#define B6_Trcd         0x2 /* 4clk */
+#define B6_SCAN         0x1 /* 9bit */
+
+#define B7_MT           0x3 /* SDRAM */
+#define B7_Trcd         0x1 /* 3clk */
+#define B7_SCAN         0x1 /* 9bit */
+
+/* REFRESH register<0x48000024> parameter */
+#define REFEN           0x1 /*  Refresh enable */
+#define TREFMD          0x0 /*  CBR(CAS before RAS)/Auto refresh */
+
+//                 Trp: Row precharge time
+// K4S561632 datasheet: Min(Trp) value should be 18/20ns;
+// EM63A165 datasheet:  Min value should be 15/20ns;
+#define Trp             0x2 /*  4clk */
+
+//                Trc:  Row cycle time
+// K4S561632 datasheet: Min value should be 60/65ns;
+// EM63A165 datasheet:  Min value should be 60/63ns;
+// S3C2440  datasheet:  REFRESH register describe: SDRAM Row cycle time: Trc=Tsrc+Trp
+#define Tsrc            0x2 /* 6clk, so Trc=Tsrc+Trp=6+3=9clk */
+
+// K4S561632 datasheet: 64ms refresh period (8K Cycle):  64000/8192=7.81us
+// EM63A165  datasheet: 8192 refresh cycles/64ms:        64000/8192=7.81us
+// S3C2440   datasheet: REFRESH Register Refresh period = (2^11-refresh_count+1)/HCLK
+//                      So Refresh count = 2^11 + 1 - 100x7.81 = 1268
+#define REFCNT          1268
+//#define REFCNT          489 /* HCLK=100Mhz, (2048+1-15.6*100) */
+
diff --git a/linux-bsp/bootstrap/build.sh b/linux-bsp/bootstrap/build.sh
new file mode 100755
index 0000000..b6be46b
--- /dev/null
+++ b/linux-bsp/bootstrap/build.sh
@@ -0,0 +1,52 @@
+#!/bin/bash
+
+BOARD=fl2440
+TFTP_PATH=/tftp
+IMGS_PATH=../images
+IMG_FILES=bootstrap-${BOARD}.bin
+
+CROSSTOOL=/opt/xtools/arm920t/bin/arm-linux-
+
+JOBS=`cat /proc/cpuinfo |grep "processor"|wc -l`
+
+set -e
+
+function do_clean()
+{
+    rm -f ${IMG_FILES}
+    rm -f cscope* tags
+    make clean
+}
+
+function do_build()
+{
+    sed -i "s|^CROSS_COMPILE.*|CROSS_COMPILE\t?=  ${CROSSTOOL}|g" makefile
+    make 
+    cp bootstrap.bin ${IMG_FILES}
+}
+
+function do_install()
+{
+    if [ -d $TFTP_PATH ] ;then 
+        echo "cp ${IMG_FILES} $TFTP_PATH"
+        cp ${IMG_FILES} $TFTP_PATH
+    fi
+
+    if [ -d ${IMGS_PATH} ] ; then
+        echo "cp ${IMG_FILES} $IMGS_PATH"
+        cp ${IMG_FILES} $IMGS_PATH
+    fi
+}
+
+if [ "$1" == "clean" ] ; then 
+
+    do_clean
+    exit 0;
+
+fi
+
+do_build
+
+do_install
+
+
diff --git a/linux-bsp/bootstrap/makefile b/linux-bsp/bootstrap/makefile
new file mode 100644
index 0000000..93b294d
--- /dev/null
+++ b/linux-bsp/bootstrap/makefile
@@ -0,0 +1,55 @@
+# ***********************************************************************
+# *        File:  makefile
+# *     Version:  1.0.0
+# *   Copyright:  2011 (c) Guo Wenxue <guowenxue@gmail.com>
+# * Description:  Makefile used to cross compile the ASM and C source code
+# *   ChangeLog:  1, Release initial version on "Mon Mar 21 21:09:52 CST 2011"
+# *
+# ***********************************************************************
+
+BINAME = bootstrap
+TEXTBASE = 0x33000000
+INST_PATH=${PWD}/../../../bin
+
+CROSS_COMPILE	?=  /opt/xtools/arm920t/bin/arm-linux-
+CC      = $(CROSS_COMPILE)gcc
+LD      = $(CROSS_COMPILE)ld
+AR      = $(CROSS_COMPILE)ar
+OBJCOPY = $(CROSS_COMPILE)objcopy
+OBJDUMP = $(CROSS_COMPILE)objdump
+STRIP   = $(CROSS_COMPILE)strip
+READELF = $(CROSS_COMPILE)readelf
+
+CFLAGS  = -g -O2 -Wall -nostdinc -nostdlib -fno-builtin
+AFLAGS  = $(CFLAGS) -D__ASSEMBLY__
+
+LDFLAGS  = -Ttext $(TEXTBASE)
+
+SRC_C   = $(wildcard *.c)
+SRC_S   = $(wildcard *.S)
+OBJ_C   = $(patsubst %.c,%.o,$(SRC_C)) 
+OBJ_S   = $(patsubst %.S,%.o,$(SRC_S)) 
+
+OBJ_ALL = $(OBJ_C) $(OBJ_S) 
+
+.PHONY : all 
+all: ${OBJ_ALL}
+	${LD} $(LDFLAGS) -o ${BINAME}.elf ${OBJ_ALL}
+	${OBJCOPY} -O binary -S ${BINAME}.elf ${BINAME}.bin
+	@rm -f *.elf *.o
+	make install
+
+%.o: %.S
+	        $(CC) $(AFLAGS) -c -o $@ $<
+%.o: %.c
+	        $(CC) $(CFLAGS) -c -o $@ $<
+
+install:
+	cp -f ${BINAME}.bin ${INST_PATH} 
+
+uninstall:
+	rm -f ${INST_PATH}/${BINAME}.bin  
+
+clean:
+	@rm -f *.elf *.o
+	@rm -f ${BINAME}.bin
diff --git a/linux-bsp/build.sh b/linux-bsp/build.sh
new file mode 100755
index 0000000..1e9efae
--- /dev/null
+++ b/linux-bsp/build.sh
@@ -0,0 +1,293 @@
+#!/bin/bash
+# Description: This shell script used to build linux system SDK. You can 
+#              use command line argument to specify build target, or select 
+#              it by hand if no argument given by command line. More detail
+#              information can refer to the help message.
+#
+#      Author: guowenxue <guowenxue@gmail.com>
+#     Version: 1.0.0  
+
+
+PROJ_PATH=`pwd`
+
+CROSSTOOL=/opt/xtools/arm920t/bin/arm-linux-
+
+BOARD=fl2440
+PACK_PATH=${PROJ_PATH}/tarballs
+PATCH_PATH=${PROJ_PATH}/patches
+PATCH_SUFIX=${BOARD}.patch
+
+KERNEL_SRC=linux-3.0
+UBOOT_SRC=u-boot-2010.09
+BOOTSTRAP_SRC=bootstrap
+
+TARBALL_FTP=ftp://master.iot-yun.club/src/
+
+
+ROOTFS_SRC=rootfs
+ROOTFS_IMG=rootfs-${BOARD}.ubi
+
+TFTP_PATH=/tftp
+IMGS_PATH=images
+
+target=
+
+function show_help()
+{
+	printf "Usage: $1 [system/bootloader/kernel/rootfs/clean]\n\n"
+
+	echo "system    : build all source code "
+	echo "bootloader: build bootstrap and u-boot "
+	echo "kernel    : build linux kernel "
+	echo "rootfs    : build ubifs rootfs images"
+	printf "clean     : clean the source code\n\n"
+	printf "distclean : remove all the source code\n\n"
+
+	exit 0;
+}
+
+function show_banner()
+{
+	echo "+---------------------------------------------+" 
+	printf "$1\n"
+	echo "+---------------------------------------------+"
+}
+
+function select_target()
+{
+	targets=("" "system" "bootloader" "kernel" "rootfs" "clean" "distclean")
+	echo "Please select a build target:"
+	echo "1 <system>    , build all source code "
+	echo "2 <bootloader>, build bootstrap and u-boot "
+	echo "3 <kernel>    , build linux kernel "
+	echo "4 <rootfs>    , build ubifs rootfs image"
+	echo "5 <clean>     , clean the source code"
+	echo "6 <distclean> , remove all the  source code"
+    echo ""
+
+    stty erase '^H'
+	read -p "Enter your choise [1-6] : " choice
+
+	if [ $choice -gt 6 ] ; then
+		echo "ERROR: Invalid input choice, exit now..."
+		exit 1;
+	fi
+
+	target=${targets[$choice]}
+}
+
+function check_download_packet()
+{
+    if [ ! -f ${PACK_PATH}/${SRC_DIR}.tar.bz2 ] ; then
+        if [[ $SRC =~ bootstrap ]] ; then
+            return ;
+        else 
+            show_banner "|       start download $SRC_DIR packet     |"
+            cd ${PACK_PATH}/ 
+            wget ${TARBALL_FTP}/${SRC_DIR}.tar.bz2 
+            cd -
+        fi
+    fi
+}
+
+
+# Usage: start_build [SRCDIR: linux-3.0/bootstrap/u-boot-2010.09 ]
+
+function start_build()
+{
+    SRC_DIR=$1
+
+    if [ ! -d ${SRC_DIR} ] ; then
+
+        check_download_packet ${SRC_DIR}
+
+	    show_banner "|       start decompress $SRC_DIR packet     |"
+        tar -xjf ${PACK_PATH}/${SRC_DIR}.tar.bz2 
+        cd ${SRC_DIR}
+
+        # Copy u-boot logo file 
+        echo ${SRC_DIR} | grep "u-boot" > /dev/null 
+        if [ $? == 0 ] ; then 
+            LOGO_FILE=logo-uboot.bmp
+            if [ -f ${PATCH_PATH}/${LOGO_FILE} ] ; then 
+                cp -f ${PATCH_PATH}/${LOGO_FILE} tools/logos/logo.bmp 
+            fi
+        fi
+
+        # Copy linux kernel logo file 
+        echo ${SRC_DIR} | grep "linux" > /dev/null 
+        if [ $? == 0 ] ; then 
+            LOGO_FILE=logo-kernel.ppm
+            if [ -f ${PATCH_PATH}/${LOGO_FILE} ] ; then 
+                cp -f ${PATCH_PATH}/${LOGO_FILE} drivers/video/logo/logo_linux_clut224.ppm
+            fi
+        fi
+
+        # patch for Jelliesv2
+        if [ -f ${PATCH_PATH}/${SRC_DIR}-${PATCH_SUFIX} ] ; then 
+            show_banner "|            patch for ${SRC_DIR}             |"
+
+            # Only u-boot not update cross compiler
+            echo ${SRC_DIR} | grep "u-boot" > /dev/null
+            if [ $? != 0 ] ; then
+                sed -i -e "s|^+CROSSTOOL=.*|+CROSSTOOL=${CROSSTOOL}|g" ${PATCH_PATH}/${SRC_DIR}-${PATCH_SUFIX}
+            fi
+            patch -p1 < ${PATCH_PATH}/${SRC_DIR}-${PATCH_SUFIX}
+        fi
+
+    else
+        cd ${SRC_DIR}
+    fi
+
+	show_banner "|           start $SRC_DIR build task...        |"
+    chmod a+x build.sh
+    bash build.sh
+	show_banner "|            $SRC_DIR build task over!          |"
+
+    cd -
+}
+
+function build_ubifs()
+{
+    ubinize_cfg=ubinize.cfg 
+    ubimg_tmp=ubi.img
+
+
+    # Rootfs partition size
+    partition_size=40  # MiB 
+
+    # K9F2G08: Nandflash 1 block=64 pages,  1 page = 2048
+    BLOCK_PAGES=64
+    PAGE_SIZE=2048
+
+    # Logic Erase Block Size: UBI requires 2 minimum I/O units out of each Physical Erase Block (PEB) for overhead:
+    #   1 for maintaining erase count information, and 1 for maintaining the Volume ID information. 
+
+    PEB_SIZE=`expr $PAGE_SIZE \* $BLOCK_PAGES`
+    LEB_SIZE=`expr $PEB_SIZE - 2 \* $PAGE_SIZE `
+
+    #UBI reserves 4 blocks space for management and bad PEB handling operations
+    # 2 PEBs are used to store the UBI volume table
+    # 1 PEB is reserved for wear-leveling purposes;
+    # 1 PEB is reserved for the atomic LEB change operation;
+    # a% of PEBs is reserved for handling bad EBs. The default for NAND is 1%
+
+    PEB_CNT=`expr $partition_size \* 1024 \* 1024 / ${PEB_SIZE}`
+    LEB_CNT=`expr $PEB_CNT - 4 - $PEB_CNT \/ 100 `
+
+    #echo "Parition size ${partition_size}MiB and LEB=$LEB_CNT"
+    printf "\nWARNNING: generete rootfs image need root privilege, please input sudo passwd!\n\n" 
+    set -x 
+    sudo mkfs.ubifs -F -d ${ROOTFS_SRC} -m ${PAGE_SIZE} -e ${LEB_SIZE} -c $LEB_CNT -o ${ubimg_tmp}
+    set +x
+
+    # vol_size smaller than the actual size of the partition to leave room for Ubifs internal data. 
+    # With "vol_type=dynamic", Ubifs will end up using the whole space automatically
+    vol_size=`expr ${partition_size} \- 10`
+
+    printf "[ubifs] \nmode=ubi \nimage=${ubimg_tmp} \nvol_id=0 \nvol_size=${vol_size}MiB\n" > $ubinize_cfg 
+    printf "vol_type=dynamic \nvol_name=rootfs \nvol_flags=autoresize\n" >> $ubinize_cfg
+    #cat $ubinize_cfg
+
+    set -x 
+    ubinize -o ${ROOTFS_IMG} -m ${PAGE_SIZE} -p ${PEB_SIZE} $ubinize_cfg
+    set +x
+
+    rm -f $ubimg_tmp $ubinize_cfg
+    chmod a+x ${ROOTFS_IMG}
+}
+
+function build_rootfs()
+{
+    if [ ! -d ${ROOTFS_SRC} ] ; then 
+        printf "\nWARNNING: decompress rootfs need root privilege, please input sudo passwd!\n\n" 
+        sudo tar -xjf ${PACK_PATH}/${ROOTFS_SRC}.tar.bz2
+    fi
+
+	show_banner "|           start build rootfs image...        |"
+    build_ubifs
+	show_banner "|           rootfs image build over!          |"
+
+    if [ -d ${IMGS_PATH} ] ; then
+        cp -f ${ROOTFS_IMG} ${IMGS_PATH}
+    fi
+
+    if [ -d ${TFTP_PATH} ] ; then
+        cp -f ${ROOTFS_IMG} ${TFTP_PATH}
+    fi
+
+    rm -f ${ROOTFS_IMG}
+    ls ${IMGS_PATH}
+}
+
+
+function do_clean()
+{
+    SRCS="$KERNEL_SRC $UBOOT_SRC $BOOTSTRAP_SRC"
+
+	show_banner "|         clean project source code           |"
+    
+    for dir in $SRCS
+    do
+        if [ -d $dir ] ; then
+            cd $dir
+            bash build.sh clean
+            cd -
+        fi
+    done
+}
+
+function do_distclean()
+{ 
+    if [ `id -u` != 0 ] ; then 
+        printf "\nERROR: distclean need root privilege, please use sudo!\n\n" 
+        exit ; 
+    fi 
+
+    printf "\nWARNNING: Start remove all the source code and images\n\n"
+    rm -rf $KERNEL_SRC $UBOOT_SRC rootfs ${IMGS_PATH}
+}
+
+function do_build()
+{
+	if   [ "$target" = "system" ] ; then
+        start_build ${BOOTSTRAP_SRC}
+        start_build ${UBOOT_SRC}
+        start_build ${KERNEL_SRC}
+        build_rootfs
+
+	elif [ "$target" = "bootloader" ] ; then
+        start_build ${BOOTSTRAP_SRC}
+        start_build ${UBOOT_SRC}
+
+	elif [ "$target" = "kernel" ] ; then
+        start_build ${KERNEL_SRC}
+
+	elif [ "$target" = "rootfs" ] ; then
+		build_rootfs
+
+	elif [ "$target" = "clean" ] ; then
+		do_clean
+
+	elif [ "$target" = "distclean" ] ; then
+        do_clean
+        do_distclean
+
+	else
+		show_help
+	fi
+}
+
+mkdir -p ${IMGS_PATH}
+
+# check input arguments for build target
+if [ $# -ge 1 ] ; then
+	target=$1
+else 
+	select_target
+fi
+show_banner "|        choose build target [$target]         |"
+
+do_build
+
+
diff --git a/linux-bsp/driver/Makefile b/linux-bsp/driver/Makefile
new file mode 100755
index 0000000..1fb8ad1
--- /dev/null
+++ b/linux-bsp/driver/Makefile
@@ -0,0 +1,46 @@
+#*********************************************************************************
+#      Copyright:  (C) 2017 LingYun IoT Studio <www.iot-yun.com>
+#                  All rights reserved.
+#
+#       Filename:  Makefile
+#    Description:  This Makefile used to compile the driver for FL2440
+#                      
+#        Version:  1.0.0(10/08/2011~)
+#                  Author:  Guo Wenxue <guowenxue@gmail.com>
+#      ChangeLog:  1, Release initial version on "11/11/2011 01:29:33 PM"
+#                       
+#********************************************************************************/
+
+LINUX_SRC = ${shell pwd}/../linux/linux-3.0/
+CROSS_COMPILE=/opt/xtools/arm920t/bin/arm-linux-
+INST_PATH=/tftp
+
+PWD := $(shell pwd)
+
+EXTRA_CFLAGS+=-DMODULE
+
+obj-m += kernel_hello.o
+obj-m += s3c_led.o
+obj-m += platdev_led.o
+obj-m += platdrv_led.o
+obj-m += platdrv_key.o
+
+modules:
+	@echo ${LINUX_SRC}
+	@make -C $(LINUX_SRC) M=$(PWD) modules
+	@make clear
+
+uninstall:
+	rm -f ${INST_PATH}/*.ko
+
+install: uninstall
+	cp -af *.ko ${INST_PATH}
+
+clear:
+	@rm -f *.o *.cmd *.mod.c
+	@rm -rf  *~ core .depend  .tmp_versions Module.symvers modules.order -f
+	@rm -f .*ko.cmd .*.o.cmd .*.o.d
+
+clean: clear
+	@rm -f  *.ko
+
diff --git a/linux-bsp/driver/kernel_hello.c b/linux-bsp/driver/kernel_hello.c
new file mode 100644
index 0000000..a5c8d25
--- /dev/null
+++ b/linux-bsp/driver/kernel_hello.c
@@ -0,0 +1,35 @@
+/*********************************************************************************
+ *      Copyright:  (C) 2017 LingYun IoT Studio <www.iot-yun.com>
+ *                  All rights reserved.
+ *
+ *       Filename:  kernel_hello.c
+ *    Description:  This file is the linux kernel module sample
+ *                 
+ *        Version:  1.0.0(03/16/2013~)
+ *         Author:  Guo Wenxue <guowenxue@gmail.com>
+ *      ChangeLog:  1, Release initial version on "03/16/2013 10:50:26 AM"
+ *                 
+ ********************************************************************************/
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+
+static __init int hello_init(void)
+{
+    printk(KERN_ALERT "Hello, LingYun IoT Studio!\n");
+    return 0;
+}
+
+static __exit void hello_exit(void)
+{
+    printk(KERN_ALERT "Goodbye, I have found a good job!\n");
+}
+
+module_init(hello_init);
+module_exit(hello_exit);
+
+MODULE_AUTHOR("GuoWenxue <guowenxue@gmail.com>");
+MODULE_DESCRIPTION("Linux Kernel hello module (C) LingYun IoT Studio");
+MODULE_LICENSE("Dual BSD/GPL");
+
diff --git a/linux-bsp/driver/platdev_led.c b/linux-bsp/driver/platdev_led.c
new file mode 100644
index 0000000..aa864a7
--- /dev/null
+++ b/linux-bsp/driver/platdev_led.c
@@ -0,0 +1,111 @@
+/*********************************************************************************
+ *      Copyright:  (C) 2017 LingYun IoT Studio <www.iot-yun.com>
+ *                  All rights reserved.
+ *
+ *       Filename:  platdev_led.c
+ *    Description:  This is the LED platform device
+ *                 
+ *        Version:  1.0.0(10/27/2011~)
+ *         Author:  Guo Wenxue <guowenxue@gmail.com>
+ *      ChangeLog:  1, Release initial version on "10/27/2011 11:39:10 AM"
+ *                 
+ ********************************************************************************/
+#include <linux/module.h>   
+#include <linux/init.h>    
+#include <linux/kernel.h>  
+
+#include "platdev_led.h"
+
+/* LED hardware informtation data*/ 
+static struct s3c_led_info  s3c_leds[] = {
+    [0] = {
+        .num = 1,
+        .gpio = S3C2410_GPB(5),
+        .active_level = LOWLEVEL,
+        .status = OFF,
+        .blink = ENABLE,
+    },
+    [1] = {
+        .num = 2,
+        .gpio = S3C2410_GPB(6),
+        .active_level = LOWLEVEL,
+        .status = OFF,
+        .blink = DISABLE,
+    },
+    [2] = {
+        .num = 3,
+        .gpio = S3C2410_GPB(8),
+        .active_level = LOWLEVEL,
+        .status = OFF,
+        .blink = DISABLE,
+    },
+    [3] = { 
+        .num = 4,
+        .gpio = S3C2410_GPB(10),
+        .active_level = LOWLEVEL,
+        .status = OFF,
+        .blink = DISABLE,
+    }, 
+};
+
+/*  The LED platform device private data */
+static struct s3c_led_platform_data s3c_led_data = {
+    .leds = s3c_leds,
+    .nleds = ARRAY_SIZE(s3c_leds),
+};
+
+
+static void platform_led_release(struct device * dev)
+{
+    int i;
+    struct s3c_led_platform_data *pdata = dev->platform_data; 
+
+    for(i=0; i<pdata->nleds; i++)
+    {
+        /* Turn all LED off */
+        s3c2410_gpio_setpin(pdata->leds[i].gpio, ~pdata->leds[i].active_level); 
+    }
+}
+
+static struct platform_device s3c_led_device = {
+    .name    = "s3c_led",
+    .id      = 1,
+    .dev     = 
+    {
+        .platform_data = &s3c_led_data, 
+        .release = platform_led_release,
+    },
+};
+
+
+static int __init platdev_led_init(void)
+{
+   int       rv = 0;
+
+   rv = platform_device_register(&s3c_led_device);
+   if(rv)
+   {
+        printk(KERN_ERR "%s:%d: Can't register platform device %d\n", __FUNCTION__,__LINE__, rv); 
+        return rv;
+   }
+   printk("Regist S3C LED Platform Device successfully.\n");
+
+   return 0;
+}
+
+
+static void platdev_led_exit(void)
+{
+    printk("%s():%d remove LED platform device\n", __FUNCTION__,__LINE__);
+    platform_device_unregister(&s3c_led_device);
+}
+
+module_init(platdev_led_init);
+module_exit(platdev_led_exit);
+
+MODULE_AUTHOR("GuoWenxue<guowenxue@gmail.com>");
+MODULE_DESCRIPTION("FL2440 LED driver platform device");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:s3c_platdev_led");
+
+
diff --git a/linux-bsp/driver/platdev_led.h b/linux-bsp/driver/platdev_led.h
new file mode 100644
index 0000000..a1a86f7
--- /dev/null
+++ b/linux-bsp/driver/platdev_led.h
@@ -0,0 +1,67 @@
+/*********************************************************************************
+ *      Copyright:  (C) 2017 LingYun IoT Studio <www.iot-yun.com>
+ *                  All rights reserved.
+ *
+ *       Filename:  platdev_led.h
+ *    Description:  This is the LED platform device head file
+ *                 
+ *        Version:  1.0.0(10/27/2011~)
+ *         Author:  Guo Wenxue <guowenxue@gmail.com>
+ *      ChangeLog:  1, Release initial version on "10/27/2011 11:39:10 AM"
+ *                 
+ ********************************************************************************/
+
+#ifndef  _PLATDEV_LED_H_
+#define  _PLATDEV_LED_H_
+
+#include <linux/platform_device.h>
+#include <linux/version.h>
+
+#include <mach/regs-gpio.h>
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,32)
+#include <mach/hardware.h>
+#include <mach/gpio.h>
+#include <asm/irq.h>
+#else 
+#include <asm-arm/irq.h>
+#include <asm/arch/gpio.h>
+#include <asm/arch/hardware.h>
+#endif
+
+
+
+#define ENPULLUP                    1
+#define DISPULLUP                   0
+
+#define HIGHLEVEL                   1
+#define LOWLEVEL                    0
+
+#define INPUT                       1
+#define OUTPUT                      0
+
+#define OFF                         0
+#define ON                          1
+
+#define ENABLE                      1
+#define DISABLE                     0
+
+/*  LED hardware informtation structure*/
+struct s3c_led_info
+{
+    unsigned char           num;              /* The LED number  */
+    unsigned int            gpio;             /* Which GPIO the LED used */  
+    unsigned char           active_level;     /* The GPIO pin level(HIGHLEVEL or LOWLEVEL) to turn on or off  */
+    unsigned char           status;           /* Current LED status: OFF/ON */
+    unsigned char           blink;            /* Blink or not */           
+};
+
+/*  The LED platform device private data structure */
+struct s3c_led_platform_data
+{
+    struct s3c_led_info    *leds;
+    int                     nleds;
+};
+
+
+#endif   /* ----- #ifndef _PLATDEV_LED_H_  ----- */
diff --git a/linux-bsp/driver/platdrv_key.c b/linux-bsp/driver/platdrv_key.c
new file mode 100644
index 0000000..cdc39f0
--- /dev/null
+++ b/linux-bsp/driver/platdrv_key.c
@@ -0,0 +1,339 @@
+/*********************************************************************************
+ *      Copyright:  (C) 2016 Guo Wenxue<guowenxue@aliyun.com>
+ *                  All rights reserved.
+ *
+ *       Filename:  platdev_key.c
+ *    Description:  This file is the keypad platform driver 
+ *                 
+ *        Version:  1.0.0(07/26/2016)
+ *         Author:  Guo Wenxue <guowenxue@aliyun.com>
+ *      ChangeLog:  1, Release initial version on "07/26/2016 05:01:25 PM"
+ *                 
+ ********************************************************************************/
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/platform_device.h>
+#include <linux/input.h>
+#include <linux/irq.h>
+#include <linux/interrupt.h>
+#include <mach/hardware.h>
+#include <asm/gpio.h>
+#include <asm/irq.h>
+#include <linux/slab.h>
+#include <mach/regs-gpio.h>
+
+/* 1HZ=100*jiffies 1*jiffies=10ms => 1HZ=100*10ms = 1s */
+#define CANCEL_DITHERING_DELAY          (HZ/50)   /* Remove button push down dithering timer delay 20ms  */ 
+
+
+/*+------------------------------------------------+
+  |      keyboard platform device information      |
+  +------------------------------------------------+*/
+
+/* keyboard hardware informtation structure definition */
+typedef struct s3c_kbd_info_s
+{
+    int                     code;      /* input device key code  */
+    int                     nIRQ;      /* keyboard IRQ number*/
+    unsigned int            setting;   /* keyboard IRQ Pin Setting*/
+    unsigned int            gpio;      /* keyboard GPIO port */
+} s3c_kbd_info_t;
+
+/* keyboard platform device private data structure */
+typedef struct s3c_kbd_platform_data_s
+{
+    s3c_kbd_info_t         *keys;
+    int                    nkeys;
+} s3c_kbd_platform_data_t;
+
+
+static s3c_kbd_info_t  s3c_kbd_gpios[] = {
+    [0] = {
+        .code = KEY_1,
+        .nIRQ = IRQ_EINT0,
+        .gpio = S3C2410_GPF(0),
+        .setting = S3C2410_GPF0_EINT0,
+    },
+    [1] = {
+        .code = KEY_2,
+        .nIRQ = IRQ_EINT2,
+        .gpio = S3C2410_GPF(2),
+        .setting = S3C2410_GPF2_EINT2,
+    },
+    [2] = {
+        .code = KEY_3,
+        .nIRQ = IRQ_EINT3,
+        .gpio = S3C2410_GPF(3),
+        .setting = S3C2410_GPF3_EINT3,
+    },
+    [3] = {
+        .code = KEY_4,
+        .nIRQ = IRQ_EINT4,
+        .gpio = S3C2410_GPF(4),
+        .setting = S3C2410_GPF4_EINT4,
+    },
+};
+
+/* keyboard platform device private data */
+static s3c_kbd_platform_data_t s3c_kbd_data = {
+    .keys = s3c_kbd_gpios,
+    .nkeys = ARRAY_SIZE(s3c_kbd_gpios),
+};
+
+static void platform_kbd_release(struct device * dev)
+{
+        return;
+}
+
+static struct platform_device s3c_keyboard_device = {
+    .name    = "s3c_kbd",
+    .id      = 1,
+    .dev     =
+    {
+        .platform_data = &s3c_kbd_data,
+        .release = platform_kbd_release,
+    },
+};
+
+
+/*+------------------------------------------------+
+  |      keyboard platform driver information      |
+  +------------------------------------------------+*/
+
+typedef struct s3c_kbd_s 
+{
+    struct timer_list           *timers; /* every key get a cancel dithering timer */
+    struct input_dev            *input_dev;
+    s3c_kbd_platform_data_t     *pdata;
+} s3c_kbd_t;  /*---  end of struct s3c_kbd_s  ---*/
+
+
+s3c_kbd_t                       *s3c_kbd = NULL;
+
+static irqreturn_t s3c_kbd_intterupt(int irq, void *dev_id) 
+{
+    int                         i;
+    int                         found = 0;
+    struct platform_device      *pdev =  dev_id;
+    s3c_kbd_t                   *s3c_kbd = NULL;
+    
+    s3c_kbd = platform_get_drvdata(pdev);
+
+    for(i=0; i<s3c_kbd->pdata->nkeys; i++)
+    {
+        if(irq == s3c_kbd->pdata->keys[i].nIRQ)
+        {
+            found = 1;
+            break;
+        }
+    }
+
+    if(!found) /*  An ERROR interrupt */
+        return IRQ_NONE;
+
+    mod_timer(&s3c_kbd->timers[i], jiffies+CANCEL_DITHERING_DELAY); 
+    return IRQ_HANDLED;  
+}
+
+static void  cancel_dithering_timer_handler(unsigned long data)
+{
+    int                      which =(int)data;
+    unsigned int             pinval;  
+
+    pinval = s3c2410_gpio_getpin(s3c_kbd->pdata->keys[which].gpio);
+
+    if( pinval ) 
+    {
+        //printk("s3c_kbd key[%d] code[%d] released\n", which, s3c_kbd->pdata->keys[which].code);
+        input_event(s3c_kbd->input_dev, EV_KEY, s3c_kbd->pdata->keys[which].code, 0);  
+    }
+    else
+    {
+        //printk("s3c_kbd key[%d] code[%d] pressed\n", which, s3c_kbd->pdata->keys[which].code);
+        input_event(s3c_kbd->input_dev, EV_KEY, s3c_kbd->pdata->keys[which].code, 1);  
+    }
+    
+    input_sync(s3c_kbd->input_dev);
+}
+
+static int s3c_kbd_probe(struct platform_device *pdev)
+{
+    int                         i = 0;
+    int                         rv = -ENOMEM;
+    struct input_dev            *input_dev = NULL;
+    s3c_kbd_platform_data_t     *pdata = pdev->dev.platform_data;
+
+    /* malloc s3c_kbd struct */
+    s3c_kbd = kmalloc(sizeof(s3c_kbd_t), GFP_KERNEL);
+    if( !s3c_kbd )
+    {
+        printk("error: s3c_kbd_probe kmalloc() for s3c_kbd failure\n");
+        goto fail;
+    }
+    memset(s3c_kbd, 0, sizeof(s3c_kbd_t));
+
+    /* malloc cancel dithering timer for every key */
+    s3c_kbd->timers = (struct timer_list *) kmalloc(pdata->nkeys*sizeof(struct timer_list), GFP_KERNEL);
+    if( !s3c_kbd->timers )
+    {
+        printk("error: s3c_kbd_probe kmalloc() for s3c_kbd timers failure\n");
+        goto fail;
+    }
+    memset(s3c_kbd->timers, 0, pdata->nkeys*sizeof(struct timer_list));
+
+    /* malloc input_dev for keyboard */
+    input_dev=input_allocate_device();
+    if( !input_dev )
+    {
+        printk("error: s3c_kbd_probe input_allocate_device() failure\n");
+        goto fail;
+    }
+
+    /* setup input_dev  */
+    input_dev->name = pdev->name;
+    input_dev->dev.parent = &pdev->dev;
+    input_dev->id.bustype = BUS_HOST;
+    input_dev->id.vendor = 0x0001;
+    input_dev->id.product = 0x0001;
+    input_dev->id.version = 0x0100;
+
+    set_bit(EV_KEY,input_dev->evbit);  
+    set_bit(EV_REP,input_dev->evbit); 
+
+    /* Initialize all the keys and interrupt */
+    for(i=0; i<pdata->nkeys; i++)
+    {
+        set_bit(pdata->keys[i].code, input_dev->keybit);
+        s3c2410_gpio_cfgpin(pdata->keys[i].gpio, pdata->keys[i].setting);
+        irq_set_irq_type(pdata->keys[i].nIRQ, IRQ_TYPE_EDGE_BOTH);
+        
+        rv = request_irq(pdata->keys[i].nIRQ, s3c_kbd_intterupt, IRQF_DISABLED, pdev->name, pdev);
+        if( rv )
+        {
+            printk("error: request IRQ[%d] for key<%d> failure\n", pdata->keys[i].nIRQ, i);
+            rv = -EBUSY;
+            goto fail;
+        }
+        
+        //printk("s3c_kbd request IRQ[%d] for key<%d> ok\n", pdata->keys[i].nIRQ, i);
+
+         /* Initialize all the keys cancel dithering timer */
+        setup_timer(&s3c_kbd->timers[i], cancel_dithering_timer_handler, i);
+    }
+
+    /* register input device */
+    rv = input_register_device(input_dev);
+    if( rv )
+    {
+        printk("error: s3c_kbd_probe input_register_device error!\n");
+        goto fail;
+    }
+
+    /* set s3c_kbd as private data in pdev */
+    s3c_kbd->input_dev = input_dev;
+    s3c_kbd->pdata = pdata;
+    platform_set_drvdata(pdev, s3c_kbd);
+
+    printk("s3c_kbd_probe ok\n");
+    return 0;
+
+fail:
+    while(i--)
+    {
+        disable_irq(pdata->keys[i].nIRQ);
+        free_irq(pdata->keys[i].nIRQ, pdev);
+        del_timer( &s3c_kbd->timers[i] );
+    }
+
+    if(input_dev)
+    {
+        input_free_device(input_dev);
+    }
+
+    if(s3c_kbd && s3c_kbd->timers)
+    {
+        kfree(s3c_kbd->timers);
+    }
+
+    if(s3c_kbd)
+    {
+        kfree(s3c_kbd);
+    }
+    printk("s3c_kbd_probe failed\n");
+
+    return -ENODEV;
+}
+
+static int s3c_kbd_remove(struct platform_device *pdev)
+{
+    int                         i = 0;
+    s3c_kbd_t                   *s3c_kbd = platform_get_drvdata(pdev);
+
+    for(i=0; i<s3c_kbd->pdata->nkeys; i++)
+    {
+        del_timer( &s3c_kbd->timers[i] );
+        disable_irq(s3c_kbd->pdata->keys[i].nIRQ);
+        free_irq(s3c_kbd->pdata->keys[i].nIRQ, pdev);
+    }
+
+    input_unregister_device(s3c_kbd->input_dev);
+
+    kfree(s3c_kbd->timers);
+    kfree(s3c_kbd);
+
+    printk("s3c_kbd_remove ok\n");
+
+    return 0;
+}
+
+static struct platform_driver s3c_keyboard_driver = {
+     .probe      = s3c_kbd_probe,
+     .remove     = s3c_kbd_remove,
+     .driver     = {
+         .name       = "s3c_kbd",
+         .owner      = THIS_MODULE,
+     },
+};
+
+static int __init s3c_keyboard_drv_init(void)
+{
+    int            rv;
+
+    rv = platform_device_register(&s3c_keyboard_device);
+    if(rv)
+    {
+        printk("S3C keyboard platform device register failure\n");
+        return rv;
+    }
+
+    rv = platform_driver_register(&s3c_keyboard_driver);
+    if(rv)
+    {
+        printk("s3c keyboard platform driver register failure\n");
+        platform_device_unregister(&s3c_keyboard_device);
+        return rv;
+    }
+
+    printk("s3c keyboard platform driver register ok\n");
+    return 0;
+}
+
+static void __exit s3c_keyboard_drv_exit(void)
+{
+    printk("s3c keyboard driver exit\n");
+
+    platform_device_unregister(&s3c_keyboard_device);
+    platform_driver_unregister(&s3c_keyboard_driver);
+
+    return ;
+}
+
+module_init(s3c_keyboard_drv_init);
+module_exit(s3c_keyboard_drv_exit);
+
+MODULE_DESCRIPTION("FL2440 board keyboard input driver platform_driver");
+MODULE_AUTHOR("Guo Wenxue<guowenxue@gmail.com>");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:FL2440 keyboard driver");
+
diff --git a/linux-bsp/driver/platdrv_led.c b/linux-bsp/driver/platdrv_led.c
new file mode 100644
index 0000000..02d7bd2
--- /dev/null
+++ b/linux-bsp/driver/platdrv_led.c
@@ -0,0 +1,297 @@
+/*********************************************************************************
+ *      Copyright:  (C)  2017 LingYun IoT Studio <www.iot-yun.com> 
+ *                  All rights reserved.
+ *
+ *       Filename:  platdrv_led.c
+ *    Description:  This is the common LED driver runs on S3C24XX.
+ *                 
+ *        Version:  1.0.0(10/27/2011~)
+ *         Author:  Guo Wenxue <guowenxue@gmail.com>
+ *      ChangeLog:  1, Release initial version on "10/27/2011 11:39:10 AM"
+ *                 
+ ********************************************************************************/
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/device.h>
+#include <linux/fs.h>
+#include <linux/cdev.h>
+#include <linux/version.h>
+
+#include "platdev_led.h"
+
+#define TIMER_TIMEOUT             40
+
+#define PLATDRV_MAGIC             0x60
+#define LED_OFF                   _IO (PLATDRV_MAGIC, 0x18)
+#define LED_ON                    _IO (PLATDRV_MAGIC, 0x19)
+#define LED_BLINK                 _IO (PLATDRV_MAGIC, 0x20)
+
+static int dev_major = 0;
+
+struct led_device
+{
+    struct s3c_led_platform_data    *data;
+    struct cdev                     cdev;
+    struct class                    *dev_class;
+    struct timer_list               blink_timer;
+} led_device;
+
+
+void led_timer_handler(unsigned long data)
+{ 
+    int  i; 
+    struct s3c_led_platform_data *pdata = (struct s3c_led_platform_data *)data;
+
+    for(i=0; i<pdata->nleds; i++) 
+    { 
+        if(ON == pdata->leds[i].status)
+        {
+              s3c2410_gpio_setpin(pdata->leds[i].gpio, pdata->leds[i].active_level); 
+        }
+        else
+        {
+              s3c2410_gpio_setpin(pdata->leds[i].gpio, ~pdata->leds[i].active_level); 
+        }
+
+        if(ENABLE == pdata->leds[i].blink )  /* LED should blink */
+        {
+            /* Switch status between 0 and 1 to turn LED ON or off */
+            pdata->leds[i].status = pdata->leds[i].status ^ 0x01;  
+        }
+
+        mod_timer(&(led_device.blink_timer), jiffies + TIMER_TIMEOUT);
+    }
+}
+
+
+static int led_open(struct inode *inode, struct file *file)
+{ 
+    struct led_device *pdev ;
+    struct s3c_led_platform_data *pdata;
+
+    pdev = container_of(inode->i_cdev,struct led_device, cdev);
+    pdata = pdev->data;
+
+    file->private_data = pdata;
+
+    return 0;
+}
+
+
+static int led_release(struct inode *inode, struct file *file)
+{ 
+    return 0;
+}
+
+static void print_led_help(void)
+{
+    printk("Follow is the ioctl() command for LED driver:\n");
+    printk("Turn LED on command        : %u\n", LED_ON);
+    printk("Turn LED off command       : %u\n", LED_OFF);
+    printk("Turn LED blink command     : %u\n", LED_BLINK);
+}
+
+/* compatible with kernel version >=2.6.38*/
+static long led_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
+{ 
+    struct s3c_led_platform_data *pdata = file->private_data;
+
+    switch (cmd)
+    {
+        case LED_OFF:
+            if(pdata->nleds <= arg)
+            {
+               printk("LED%ld doesn't exist\n", arg);  
+               return -ENOTTY;
+            }
+            pdata->leds[arg].status = OFF;
+            pdata->leds[arg].blink = DISABLE;
+            break;
+
+        case LED_ON:
+            if(pdata->nleds <= arg)
+            {
+               printk("LED%ld doesn't exist\n", arg);  
+               return -ENOTTY;
+            }
+            pdata->leds[arg].status = ON;
+            pdata->leds[arg].blink = DISABLE;
+            break;
+
+        case LED_BLINK:
+            if(pdata->nleds <= arg)
+            {
+               printk("LED%ld doesn't exist\n", arg);  
+               return -ENOTTY;
+            }
+            pdata->leds[arg].blink = ENABLE;
+            pdata->leds[arg].status = ON;
+            break;
+
+        default: 
+            printk("LED driver don't support ioctl command=%d\n", cmd); 
+            print_led_help();
+            return -EINVAL;
+
+    }
+    return 0;
+}
+
+
+static struct file_operations led_fops = { 
+    .owner = THIS_MODULE, 
+    .open = led_open, 
+    .release = led_release, 
+    .unlocked_ioctl = led_ioctl, /* compatible with kernel version >=2.6.38*/
+};
+
+
+static int s3c_led_probe(struct platform_device *dev)
+{
+    struct s3c_led_platform_data *pdata = dev->dev.platform_data; 
+    int result = 0;
+    int i;
+    dev_t devno;
+
+    /* Initialize the LED status */
+    for(i=0; i<pdata->nleds; i++)
+    {
+         s3c2410_gpio_cfgpin(pdata->leds[i].gpio, S3C2410_GPIO_OUTPUT);
+         if(ON == pdata->leds[i].status)
+         {
+            s3c2410_gpio_setpin(pdata->leds[i].gpio, pdata->leds[i].active_level); 
+         }
+         else
+         {
+            s3c2410_gpio_setpin(pdata->leds[i].gpio, ~pdata->leds[i].active_level); 
+         }
+    }
+
+    /*  Alloc the device for driver */
+    if (0 != dev_major) 
+    { 
+        devno = MKDEV(dev_major, 0); 
+        result = register_chrdev_region(devno, 1, "led"); 
+    } 
+    else 
+    { 
+        result = alloc_chrdev_region(&devno, 0, 1, "led"); 
+        dev_major = MAJOR(devno); 
+    }
+
+    /* Alloc for device major failure */ 
+    if (result < 0) 
+    { 
+        printk("LED driver can't get major %d\n", dev_major); 
+        return result; 
+    }
+
+    /* Initialize button structure and register cdev*/
+    memset(&led_device, 0, sizeof(led_device));
+    led_device.data = dev->dev.platform_data;
+    cdev_init (&(led_device.cdev), &led_fops);
+    led_device.cdev.owner  = THIS_MODULE;
+
+    result = cdev_add (&(led_device.cdev), devno , 1); 
+    if (result) 
+    { 
+        printk (KERN_NOTICE "error %d add led device", result ); 
+        goto ERROR; 
+    } 
+    
+    led_device.dev_class = class_create(THIS_MODULE, "led"); 
+    if(IS_ERR(led_device.dev_class)) 
+    { 
+        printk("LED driver create class failure\n"); 
+        result =  -ENOMEM; 
+        goto ERROR; 
+    }
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,24)     
+    device_create(led_device.dev_class, NULL, devno, NULL, "led");
+#else
+    device_create (led_device.dev_class, NULL, devno, "led");
+#endif
+
+    /*  Initial the LED blink timer */
+    init_timer(&(led_device.blink_timer));
+    led_device.blink_timer.function = led_timer_handler;
+    led_device.blink_timer.data = (unsigned long)pdata;
+    led_device.blink_timer.expires  = jiffies + TIMER_TIMEOUT;
+    add_timer(&(led_device.blink_timer)); 
+
+    printk("S3C led driver version 1.0.0 initiliazed.\n"); 
+
+    return 0;
+               
+
+ERROR: 
+    printk("S3C led driver version 1.0.0 install failure.\n"); 
+    cdev_del(&(led_device.cdev)); 
+
+    unregister_chrdev_region(devno, 1); 
+    return result;
+
+}
+
+static int s3c_led_remove(struct platform_device *dev)
+{
+    dev_t devno = MKDEV(dev_major, 0);
+
+    del_timer(&(led_device.blink_timer));
+
+    cdev_del(&(led_device.cdev)); 
+    device_destroy(led_device.dev_class, devno); 
+    class_destroy(led_device.dev_class); 
+    
+    unregister_chrdev_region(devno, 1); 
+    printk("S3C led driver removed\n" );
+
+    return 0;
+}
+
+
+static struct platform_driver s3c_led_driver = { 
+    .probe      = s3c_led_probe, 
+    .remove     = s3c_led_remove, 
+    .driver     = { 
+        .name       = "s3c_led", 
+        .owner      = THIS_MODULE, 
+    },
+};
+
+
+static int __init platdrv_led_init(void)
+{
+   int       rv = 0;
+
+   rv = platform_driver_register(&s3c_led_driver);
+   if(rv)
+   {
+        printk(KERN_ERR "%s:%d: Can't register platform driver %d\n", __FUNCTION__,__LINE__, rv); 
+        return rv;
+   }
+   printk("Regist S3C LED Platform Driver successfully.\n");
+
+   return 0;
+}
+
+
+static void platdrv_led_exit(void)
+{
+    printk("%s():%d remove LED platform drvier\n", __FUNCTION__,__LINE__);
+    platform_driver_unregister(&s3c_led_driver);
+}
+
+module_init(platdrv_led_init);
+module_exit(platdrv_led_exit);
+
+module_param(dev_major, int, S_IRUGO);
+
+MODULE_AUTHOR("GuoWenxue<guowenxue@gmail.com>");
+MODULE_DESCRIPTION("FL2440 LED driver platform driver");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:s3c_platdrv_led");
+
diff --git a/linux-bsp/driver/s3c_led.c b/linux-bsp/driver/s3c_led.c
new file mode 100644
index 0000000..6f3b804
--- /dev/null
+++ b/linux-bsp/driver/s3c_led.c
@@ -0,0 +1,281 @@
+/*********************************************************************************
+ *      Copyright:  (C) 2017 LingYun IoT Studio <www.iot-yun.com>
+ *                  All rights reserved.
+ *
+ *       Filename:  s3c_led.c
+ *    Description:  This file 
+ *                 
+ *        Version:  1.0.0(07/26/2012~)
+ *         Author:  Guo Wenxue <guowenxue@gmail.com>
+ *      ChangeLog:  1, Release initial version on "07/26/2012 10:03:40 PM"
+ *                 
+ ********************************************************************************/
+
+#include <linux/module.h>   /* Every Linux kernel module must include this head */
+#include <linux/init.h>     /* Every Linux kernel module must include this head */
+#include <linux/kernel.h>   /* printk() */
+#include <linux/fs.h>       /* struct fops */
+#include <linux/errno.h>    /* error codes */
+#include <linux/cdev.h>     /* cdev_alloc()  */
+#include <asm/io.h>         /* ioremap()  */
+#include <linux/ioport.h>   /* request_mem_region() */
+
+#include <asm/ioctl.h>      /* Linux kernel space head file for macro _IO() to generate ioctl command  */
+#include <linux/printk.h>   /* Define log level KERN_DEBUG */
+
+#define LED_NUM                   4
+
+#define DISABLE                   0
+#define ENABLE                    1
+
+#define GPIO_INPUT                0x00
+#define GPIO_OUTPUT               0x01
+
+
+#define PLATDRV_MAGIC             0x60
+#define LED_OFF                   _IO (PLATDRV_MAGIC, 0x18)
+#define LED_ON                    _IO (PLATDRV_MAGIC, 0x19)
+
+#define S3C_GPB_BASE              0x56000010
+#define S3C_GPB_LEN               0x10        /* 0x56000010~0x56000020  */
+#define GPBCON_OFFSET             0
+#define GPBDAT_OFFSET             4
+#define GPBUP_OFFSET              8
+
+static void __iomem               *gpbbase = NULL;
+
+#define read_reg32(addr)          *(volatile unsigned int *)(addr)
+#define write_reg32(addr, val)    *(volatile unsigned int *)(addr) = (val)
+
+int led[LED_NUM] = {5,6,8,10};  /* Four LEDs use GPB5,GPB6,GPB8,GPB10 */
+int dev_count = ARRAY_SIZE(led);
+
+int dev_major = 0;
+int dev_minor = 0;
+int debug = DISABLE;
+
+static struct cdev      *led_cdev;
+
+
+static int s3c_hw_init(void)
+{
+    int            i;
+    unsigned int   regval; 
+
+    if(!request_mem_region(S3C_GPB_BASE, S3C_GPB_LEN, "s3c2440 led"))
+    {
+        printk(KERN_ERR "request_mem_region failure!\n");
+        return -EBUSY;
+    }
+
+    if( !(gpbbase=(unsigned int  *)ioremap(S3C_GPB_BASE, S3C_GPB_LEN)) )
+    {
+        release_mem_region(S3C_GPB_BASE, S3C_GPB_LEN);
+        printk(KERN_ERR "release_mem_region failure!\n");
+        return -ENOMEM;
+    }
+
+
+    for(i=0; i<dev_count; i++)
+    {
+        /* Set GPBCON register, set correspond GPIO port as input or output mode  */
+        regval = read_reg32(gpbbase+GPBCON_OFFSET);
+        regval &= ~(0x3<<(2*led[i]));   /* Clear the currespond LED GPIO configure register */
+        regval |= GPIO_OUTPUT<<(2*led[i]); /* Set the currespond LED GPIO as output mode */
+        write_reg32(gpbbase+GPBCON_OFFSET, regval);
+
+        /* Set GPBUP register, set correspond GPIO port pull up resister as enable or disable  */
+        regval = read_reg32(gpbbase+GPBUP_OFFSET);
+        regval |= (0x1<<led[i]);  /* Disable pull up resister */
+        write_reg32(gpbbase+GPBUP_OFFSET, regval);
+
+        /* Set GPBDAT register, set correspond GPIO port power level as high level or low level */
+        regval = read_reg32(gpbbase+GPBDAT_OFFSET);
+        regval |= (0x1<<led[i]);  /* This port set to high level, then turn LED off */
+        write_reg32(gpbbase+GPBDAT_OFFSET, regval);
+    }
+
+    return 0;
+}
+
+
+static void turn_led(int which, unsigned int cmd)
+{
+    unsigned int   regval; 
+
+    regval = read_reg32(gpbbase+GPBDAT_OFFSET);
+
+    if(LED_ON == cmd)
+    {
+        regval &= ~(0x1<<led[which]); /*  Turn LED On */
+    }
+    else if(LED_OFF == cmd)
+    {
+        regval |= (0x1<<led[which]);  /*  Turn LED off */
+    }
+
+    write_reg32(gpbbase+GPBDAT_OFFSET, regval);
+}
+
+static void s3c_hw_term(void)
+{
+    int            i;
+    unsigned int   regval; 
+
+    for(i=0; i<dev_count; i++)
+    {
+        regval = read_reg32(gpbbase+GPBDAT_OFFSET);
+        regval |= (0x1<<led[i]);  /* Turn LED off */
+        write_reg32(gpbbase+GPBDAT_OFFSET, regval);
+    }
+
+    release_mem_region(S3C_GPB_BASE, S3C_GPB_LEN);
+    iounmap(gpbbase);
+}
+
+
+static int led_open(struct inode *inode, struct file *file)
+{
+    int minor = iminor(inode);
+
+    file->private_data = (void *)minor;
+
+    printk(KERN_DEBUG "/dev/led%d opened.\n", minor);
+    return 0;
+}
+
+static int led_release(struct inode *inode, struct file *file)
+{
+    printk(KERN_DEBUG "/dev/led%d closed.\n", iminor(inode));
+
+    return 0;
+}
+
+static void print_help(void)
+{
+    printk("Follow is the ioctl() commands for led driver:\n");
+    printk("Turn LED on command  : %u\n", LED_ON);
+    printk("Turn LED off command : %u\n", LED_OFF);
+
+    return;
+}
+
+static long led_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
+{
+    int which = (int)file->private_data;
+
+    switch (cmd)
+    {
+        case LED_ON:
+
+            turn_led(which, LED_ON);
+            break;
+
+        case LED_OFF:
+            turn_led(which, LED_OFF);
+            break;
+    
+        default:
+            printk(KERN_ERR "LED driver don't support ioctl command=%d\n", cmd);
+            print_help();
+            break;
+    }
+
+    return 0;
+}
+
+
+static struct file_operations led_fops = 
+{
+    .owner = THIS_MODULE,
+    .open = led_open,
+    .release = led_release,
+    .unlocked_ioctl = led_ioctl,
+};
+
+static int __init s3c_led_init(void)
+{
+    int                    result;
+    dev_t                  devno;
+
+    if( 0 != s3c_hw_init() )
+    {
+        printk(KERN_ERR "s3c2440 LED hardware initialize failure.\n");
+        return -ENODEV;
+    }
+
+    /*  Alloc the device for driver */
+    if (0 != dev_major) /*  Static */
+    {
+        devno = MKDEV(dev_major, 0);
+        result = register_chrdev_region (devno, dev_count, "led");
+    }
+    else
+    {
+        result = alloc_chrdev_region(&devno, dev_minor, dev_count, "led");
+        dev_major = MAJOR(devno);
+    }
+
+    /*  Alloc for device major failure */
+    if (result < 0)
+    {
+        printk(KERN_ERR "S3C led driver can't use major %d\n", dev_major);
+        return -ENODEV;
+    } 
+    printk(KERN_DEBUG "S3C led driver use major %d\n", dev_major);
+
+    if(NULL == (led_cdev=cdev_alloc()) )
+    {
+        printk(KERN_ERR "S3C led driver can't alloc for the cdev.\n");
+        unregister_chrdev_region(devno, dev_count);
+        return -ENOMEM;
+    }
+    
+    led_cdev->owner = THIS_MODULE;
+    cdev_init(led_cdev, &led_fops);
+
+    result = cdev_add(led_cdev, devno, dev_count);
+    if (0 != result)
+    {   
+        printk(KERN_INFO "S3C led driver can't reigster cdev: result=%d\n", result); 
+        goto ERROR;
+    }
+
+            
+    printk(KERN_ERR "S3C led driver[major=%d] version 1.0.0 installed successfully!\n", dev_major);
+    return 0;
+
+
+ERROR:
+    printk(KERN_ERR "S3C led driver installed failure.\n");
+    cdev_del(led_cdev);
+    unregister_chrdev_region(devno, dev_count);
+    return result;
+}
+
+static void __exit s3c_led_exit(void)
+{
+    dev_t devno = MKDEV(dev_major, dev_minor);
+
+    s3c_hw_term();
+
+    cdev_del(led_cdev);
+    unregister_chrdev_region(devno, dev_count);
+
+    printk(KERN_ERR "S3C led driver version 1.0.0 removed!\n");
+
+    return ;
+}
+
+
+/* These two functions defined in <linux/init.h> */
+module_init(s3c_led_init);
+module_exit(s3c_led_exit);
+
+module_param(debug, int, S_IRUGO);
+module_param(dev_major, int, S_IRUGO);
+
+MODULE_AUTHOR("guowenxue@LingYun IoT Studio");
+MODULE_DESCRIPTION("FL2440 LED linux lowlevel API driver");
+MODULE_LICENSE("GPL");
+
diff --git a/linux-bsp/driver/test/makefile b/linux-bsp/driver/test/makefile
new file mode 100644
index 0000000..e4a9c8f
--- /dev/null
+++ b/linux-bsp/driver/test/makefile
@@ -0,0 +1,46 @@
+#*********************************************************************************
+#      Copyright:  (C) 2017 LingYun IoT Studio <www.iot-yun.com>
+#                  All rights reserved.
+#
+#       Filename:  Makefile
+#    Description:  This Makefile used to compile all the C source code file in current 
+#                  folder to respective excutable binary files.
+#                      
+#        Version:  1.0.0(10/08/2011~)
+#                  Author:  Guo Wenxue <guowenxue@gmail.com>
+#      ChangeLog:  1, Release initial version on "11/11/2011 01:29:33 PM"
+#                       
+#********************************************************************************/
+
+PWD=$(shell pwd)
+INSTPATH=/tftp
+
+CROSS_COMPILE=/opt/xtools/arm920t/bin/arm-linux-
+export CC=${CROSS_COMPILE}gcc
+
+CFLAGS+=-I`dirname ${PWD}`
+
+SRCFILES = $(wildcard *.c)
+BINARIES=$(SRCFILES:%.c=%)
+
+all: binaries install 
+
+binaries:  ${BINARIES} 
+	@echo " Compile over"
+
+%:  %.c 
+	$(CC) -o $@ $< $(CFLAGS)
+
+install:
+	cp $(BINARIES) ${INSTPATH}
+
+clean: 
+	@rm -f version.h 
+	@rm -f *.o $(BINARIES) 
+	@rm -rf *.gdb *.a *.so *.elf*
+
+distclean: clean
+	@rm -f  tags cscope*
+
+.PHONY: clean
+
diff --git a/linux-bsp/driver/test/test_plat_key.c b/linux-bsp/driver/test/test_plat_key.c
new file mode 100644
index 0000000..0b60311
--- /dev/null
+++ b/linux-bsp/driver/test/test_plat_key.c
@@ -0,0 +1,279 @@
+/*********************************************************************************
+ *      Copyright:  (C) 2012 Guo Wenxue<Email:guowenxue@gmail.com QQ:281143292>
+ *                  All rights reserved.
+ *
+ *       Filename:  event_button.c
+ *    Description:  This file used to test GPIO button driver builtin Linux kernel on ARM board
+ *                 
+ *        Version:  1.0.0(07/13/2012~)
+ *         Author:  Guo Wenxue <guowenxue@gmail.com>
+ *      ChangeLog:  1, Release initial version on "07/13/2012 02:46:18 PM"
+ *                 
+ ********************************************************************************/
+
+#include <stdio.h>
+#include <unistd.h>
+#include <errno.h>
+#include <string.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <libgen.h>
+#include <getopt.h>
+#include <sys/types.h>
+#include <sys/ioctl.h>
+#include <linux/input.h>
+#include <linux/kd.h>
+#include <linux/keyboard.h>
+
+#if 0 /* Just for comment here, Reference to linux-3.3/include/linux/input.h */
+struct input_event 
+{
+    struct timeval time;
+    __u16 type;  /* 0x00:EV_SYN 0x01:EV_KEY 0x04:EV_MSC 0x11:EV_LED*/
+    __u16 code;  /* key value, which key */
+    __s32 value; /* 1: Pressed  0:Not pressed  2:Always Pressed */
+};  
+#endif
+
+#define TRUE               1
+#define FALSE              0
+
+#define EV_RELEASED        0
+#define EV_PRESSED         1
+#define EV_REPEAT          2
+
+#define BUTTON_CNT         5
+
+#define MODE_POLL          0x01
+#define MODE_NORMAL        0x02
+
+void usage(char *name);
+void display_button_event(struct input_event *ev, int cnt);
+
+int main(int argc, char **argv)
+{
+    char                  *kbd_dev = NULL;
+    char                  kbd_name[256] = "Unknown";
+    int                   kbd_fd = -1;
+
+    int                   rv, opt;
+    int                   mode = MODE_NORMAL;
+    int                   size = sizeof (struct input_event);
+
+    struct input_event    ev[BUTTON_CNT]; 
+
+    struct option long_options[] = {
+        {"device", required_argument, NULL, 'd'},
+        {"poll", no_argument, NULL, 'p'},
+        {"help", no_argument, NULL, 'h'},
+        {NULL, 0, NULL, 0}
+    };
+
+    while ((opt = getopt_long(argc, argv, "d:ph", long_options, NULL)) != -1)
+    { 
+        switch (opt)
+        {
+            case 'd':
+                kbd_dev = optarg;
+                break;
+
+            case 'p':
+                mode = MODE_POLL;
+                break;
+
+            case 'h':
+                usage(argv[0]);
+                return 0;
+
+            default:
+                break;
+        }
+    }
+
+    if(NULL == kbd_dev)
+    {
+        usage(argv[0]);
+        return -1;
+    }
+
+    if ((getuid ()) != 0)
+        printf ("You are not root! This may not work...\n");
+
+
+    if ((kbd_fd = open(kbd_dev, O_RDONLY)) < 0)
+    {
+        printf("Open %s failure: %s", kbd_dev, strerror(errno));
+        return -1;
+    }
+
+    ioctl (kbd_fd, EVIOCGNAME (sizeof (kbd_name)), kbd_name);
+    printf ("Monitor input device %s (%s) event with %s mode:\n", kbd_dev, kbd_name, MODE_POLL==mode?"poll":"infilit loop");
+
+
+#if 0 /* Not implement in the Linux GPIO button driver */
+    unsigned char key_b[BUTTON_CNT/8 + 1];
+    memset(key_b, 0, sizeof(key_b));
+    if(ioctl(kbd_fd, EVIOCGKEY(sizeof(key_b)), key_b) < 0)
+    {
+        printf("EVIOCGKEY ioctl get error: %s\n", strerror(errno));
+        return -1;
+    }
+#endif
+
+#if 0 /* Not implement in the Linux GPIO button driver */
+    /* rep[0]表示在按键重复出现之前 delay的时间,rep[1]表示按键重复出现的时间间隔。 */
+    int rep[2] ={2500, 1000} ;
+    if(ioctl(kbd_fd, EVIOCSREP, rep) < 0)
+    {
+        printf("EVIOCSREP ioctl get error: %s\n", strerror(errno));
+        return -1;
+    }
+
+    if(ioctl(kbd_fd, EVIOCGREP, rep) < 0)
+    {
+        printf("EVIOCGKEY ioctl get error: %s\n", strerror(errno));
+        return -1;
+    }
+    else
+    {
+        printf("repeate speed: [0]= %d, [1] = %d/n", rep[0], rep[1]);
+    }
+#endif
+
+    while (1)
+    {
+        if(MODE_POLL==mode)
+        {
+            fd_set rds;
+            FD_ZERO(&rds);
+            FD_SET(kbd_fd, &rds);
+
+            rv = select(kbd_fd + 1, &rds, NULL, NULL, NULL);
+            if (rv < 0)
+            {
+                printf("Select() system call failure: %s\n", strerror(errno));
+                goto CleanUp;
+            }
+            else if (FD_ISSET(kbd_fd, &rds))
+            { 
+                if ((rv = read (kbd_fd, ev, size*BUTTON_CNT )) < size)
+                {
+                    printf("Reading data from kbd_fd failure: %s\n", strerror(errno));
+                    break;
+                }
+                else
+                {
+                    display_button_event(ev, rv/size);
+                }
+            }
+        }
+        else
+        {
+            if ((rv = read (kbd_fd, ev, size*BUTTON_CNT )) < size)
+            {
+                printf("Reading data from kbd_fd failure: %s\n", strerror(errno));
+                break;
+            }
+            else
+            {
+                display_button_event(ev, rv/size);
+            }
+        }
+    }
+
+CleanUp:
+    close(kbd_fd);
+
+    return 0;
+}
+
+void usage(char *name)
+{
+    char *progname = NULL;
+    char *ptr = NULL;
+
+    ptr = strdup(name);
+    progname = basename(ptr);
+
+    printf("Usage: %s [-p] -d <device>\n", progname);
+    printf(" -d[device  ] button device name\n");
+    printf(" -p[poll    ] Use poll mode, or default use infinit loop.\n");
+    printf(" -h[help    ] Display this help information\n"); 
+
+    free(ptr);
+
+    return;
+}
+
+void display_button_event(struct input_event *ev, int cnt)
+{
+    int i;
+    struct timeval        pressed_time, duration_time;
+
+    for(i=0; i<cnt; i++)
+    {
+        //printf("type:%d code:%d value:%d\n", ev[i].type, ev[i].code, ev[i].value);
+        if(EV_KEY==ev[i].type && EV_PRESSED==ev[i].value)
+        {
+            if(BTN_1 == ev[i].code)
+            {
+                pressed_time = ev[i].time;
+                printf("S1 button key[%d] pressed time: %ld.%ld\n", ev[i].code, pressed_time.tv_sec, pressed_time.tv_usec);
+            }
+            else if(BTN_2 == ev[i].code)
+            {
+                pressed_time = ev[i].time;
+                printf("S2 button key[%d] pressed time: %ld.%ld\n", ev[i].code, pressed_time.tv_sec, pressed_time.tv_usec);
+            }
+            else if(BTN_3 == ev[i].code)
+            {
+                pressed_time = ev[i].time;
+                printf("S3 button key[%d] pressed time: %ld.%ld\n", ev[i].code, pressed_time.tv_sec, pressed_time.tv_usec);
+            }
+            else if(BTN_4 == ev[i].code)
+            {
+                pressed_time = ev[i].time;
+                printf("S4 button key[%d] pressed time: %ld.%ld\n", ev[i].code, pressed_time.tv_sec, pressed_time.tv_usec);
+            }
+            else
+            {
+                pressed_time = ev[i].time;
+                printf("button key[%d]  pressed time: %ld.%ld\n", ev[i].code, pressed_time.tv_sec, pressed_time.tv_usec);
+            }
+        }
+        if(EV_KEY==ev[i].type && EV_RELEASED==ev[i].value)
+        {
+            if(BTN_1 == ev[i].code)
+            {
+                timersub(&ev[i].time, &pressed_time, &duration_time);
+                printf("S1 button key[%d] released time: %ld.%ld\n", ev[i].code, ev[i].time.tv_sec, ev[i].time.tv_usec);
+                printf("S1 button key[%d] duration time: %ld.%ld\n", ev[i].code, duration_time.tv_sec, duration_time.tv_usec);
+            }
+            else if(BTN_2 == ev[i].code)
+            {
+                timersub(&ev[i].time, &pressed_time, &duration_time);
+                printf("S2 button key[%d] released time: %ld.%ld\n", ev[i].code, ev[i].time.tv_sec, ev[i].time.tv_usec);
+                printf("S2 button key[%d] duration time: %ld.%ld\n", ev[i].code, duration_time.tv_sec, duration_time.tv_usec);
+            }
+            else if(BTN_3 == ev[i].code)
+            {
+                timersub(&ev[i].time, &pressed_time, &duration_time);
+                printf("S3 button key[%d] released time: %ld.%ld\n", ev[i].code, ev[i].time.tv_sec, ev[i].time.tv_usec);
+                printf("S3 button key[%d] duration time: %ld.%ld\n", ev[i].code, duration_time.tv_sec, duration_time.tv_usec);
+            }
+            else if(BTN_4 == ev[i].code)
+            {
+                timersub(&ev[i].time, &pressed_time, &duration_time);
+                printf("S4 button key[%d] released time: %ld.%ld\n", ev[i].code, ev[i].time.tv_sec, ev[i].time.tv_usec);
+                printf("S4 button key[%d] duration time: %ld.%ld\n", ev[i].code, duration_time.tv_sec, duration_time.tv_usec);
+            }
+            else
+            {
+                timersub(&ev[i].time, &pressed_time, &duration_time);
+                printf("button key[%d] released time: %ld.%ld\n", ev[i].code, ev[i].time.tv_sec, ev[i].time.tv_usec);
+                printf("button key[%d] duration time: %ld.%ld\n", ev[i].code, duration_time.tv_sec, duration_time.tv_usec);
+            }
+        }
+    } /*  for(i=0; i<cnt; i++) */
+}
diff --git a/linux-bsp/driver/test/test_plat_led.c b/linux-bsp/driver/test/test_plat_led.c
new file mode 100644
index 0000000..dd2261f
--- /dev/null
+++ b/linux-bsp/driver/test/test_plat_led.c
@@ -0,0 +1,72 @@
+/*********************************************************************************
+ *      Copyright:  (C) 2017 LingYun IoT Studio <www.iot-yun.com>
+ *                  All rights reserved.
+ *
+ *       Filename:  test_plat_led.c
+ *    Description:  This file used to test platdrv_led.c driver
+ *                 
+ *        Version:  1.0.0(03/15/2014)
+ *         Author:  Guo Wenxue <guowenxue@gmail.com>
+ *      ChangeLog:  1, Release initial version on "03/15/2014 02:03:22 PM"
+ *                 
+ ********************************************************************************/
+#include <stdio.h>
+#include <string.h>
+#include <stdarg.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <sys/ioctl.h>
+#include <unistd.h>
+#include <sys/select.h>
+#include <errno.h>
+
+#define LED_CNT                   4
+
+#define PLATDRV_MAGIC             0x60
+#define LED_OFF                   _IO (PLATDRV_MAGIC, 0x18)
+#define LED_ON                    _IO (PLATDRV_MAGIC, 0x19)
+#define LED_BLINK                 _IO (PLATDRV_MAGIC, 0x20)
+
+static inline msleep(unsigned long ms)
+{
+    struct timeval       tv;
+
+    tv.tv_sec = ms/1000;
+    tv.tv_usec = (ms%1000)*1000;
+
+    select(0, NULL, NULL, NULL, &tv);
+}
+
+int main (int argc, char **argv)
+{
+    int           i;
+    int           fd;
+
+    if( (fd=open("/dev/led", O_RDWR, 0755)) <  0 )
+    {
+        printf("open led device failure: %s\n", strerror(errno));
+        return 0;
+    }
+
+    for(i=0; i<LED_CNT; i++)
+       ioctl(fd, LED_BLINK, i);
+
+    sleep(3);
+
+    while(1)
+    {
+        for(i=0; i<LED_CNT; i++)
+        {
+            ioctl(fd, LED_OFF, i);
+            msleep(800);
+            ioctl(fd, LED_ON, i);
+            msleep(800);
+        }
+    }
+
+    close(fd);
+
+    return 0;
+} /* ----- End of main() ----- */
+
diff --git a/linux-bsp/driver/test/test_s3c_led.c b/linux-bsp/driver/test/test_s3c_led.c
new file mode 100644
index 0000000..35290be
--- /dev/null
+++ b/linux-bsp/driver/test/test_s3c_led.c
@@ -0,0 +1,81 @@
+/*********************************************************************************
+ *      Copyright:  (C) 2017 LingYun IoT Studio <www.iot-yun.com>
+ *                  All rights reserved.
+ *
+ *       Filename:  test_s3c_led.c
+ *    Description:  This file is used to tst s3c_led.c driver
+ *                 
+ *        Version:  1.0.0(03/15/2014)
+ *         Author:  Guo Wenxue <guowenxue@gmail.com>
+ *      ChangeLog:  1, Release initial version on "03/15/2014 02:03:22 PM"
+ *                 
+ ********************************************************************************/
+#include <stdio.h>
+#include <stdarg.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <sys/ioctl.h>
+#include <unistd.h>
+#include <sys/select.h>
+
+#define LED_CNT        4
+#define DEVNAME_LEN    10
+
+#define PLATDRV_MAGIC             0x60
+#define LED_OFF                   _IO (PLATDRV_MAGIC, 0x18)
+#define LED_ON                    _IO (PLATDRV_MAGIC, 0x19)
+
+static inline msleep(unsigned long ms)
+{
+    struct timeval       tv;
+
+    tv.tv_sec = ms/1000;
+    tv.tv_usec = (ms%1000)*1000;
+
+    select(0, NULL, NULL, NULL, &tv);
+}
+
+int main (int argc, char **argv)
+{
+    int           i;
+    int           fd[LED_CNT];
+    char          dev_name[DEVNAME_LEN]={0,0,0,0};
+
+    for(i=0; i<LED_CNT; i++)
+    {
+        snprintf(dev_name, sizeof(dev_name), "/dev/led%d", i);
+        fd[i] = open(dev_name, O_RDWR, 0755);
+        if(fd[i] < 0)
+            goto err;
+    }
+
+    while(1)
+    {
+        for(i=0; i<LED_CNT; i++)
+        {
+            ioctl(fd[i], LED_ON);
+            msleep(300);
+            ioctl(fd[i], LED_OFF);
+            msleep(300);
+        }
+    }
+
+    for(i=0; i<LED_CNT; i++)
+    {
+        close(fd[i]);
+    }
+
+    return 0;
+
+err:
+    for(i=0; i<LED_CNT; i++)
+    {
+        if(fd[i] >= 0)
+        {
+            close(fd[i]);
+        }
+    }
+    return -1;
+} /* ----- End of main() ----- */
+
diff --git a/linux-bsp/driver/x86/Makefile b/linux-bsp/driver/x86/Makefile
new file mode 100644
index 0000000..441a6de
--- /dev/null
+++ b/linux-bsp/driver/x86/Makefile
@@ -0,0 +1,29 @@
+#*********************************************************************************
+#      Copyright:  (C) 2017 LingYun IoT Studio <www.iot-yun.com>
+#                  All rights reserved.
+#
+#       Filename:  Makefile
+#    Description:  This Makefile used to compile the driver for X86
+#
+#        Version:  1.0.0(10/08/2011~)
+#                  Author:  Guo Wenxue <guowenxue@gmail.com>
+#      ChangeLog:  1, Release initial version on "11/11/2011 01:29:33 PM"
+#
+#********************************************************************************/
+
+KERNAL_DIR ?= /lib/modules/$(shell uname -r)/build
+PWD := $(shell pwd)
+
+obj-m := kernel_hello.o
+
+all: 
+	$(MAKE) -C $(KERNAL_DIR) M=$(PWD) modules
+	@make clear
+
+clear: 
+	@rm -f *.o *.cmd *.mod.c 
+	@rm -rf  *~ core .depend  .tmp_versions Module.symvers modules.order -f 
+	@rm -f .*ko.cmd .*.o.cmd .*.o.d .*.cmd *.unsigned
+
+clean:
+	@rm -f *.ko
diff --git a/linux-bsp/driver/x86/kernel_hello.c b/linux-bsp/driver/x86/kernel_hello.c
new file mode 120000
index 0000000..d169853
--- /dev/null
+++ b/linux-bsp/driver/x86/kernel_hello.c
@@ -0,0 +1 @@
+../kernel_hello.c
\ No newline at end of file
diff --git a/linux-bsp/patches/gen_patch.sh b/linux-bsp/patches/gen_patch.sh
new file mode 100755
index 0000000..55c6efa
--- /dev/null
+++ b/linux-bsp/patches/gen_patch.sh
@@ -0,0 +1,71 @@
+#!/bin/bash
+# Description: This shell script used to generate patch file
+#      Author: guowenxue <guowenxue@gmail.com>
+#     Version: 1.0.0  
+
+PROJ_PATH=`pwd`
+
+PACK_PATH=${PROJ_PATH}/tarballs
+PATCH_PATH=${PROJ_PATH}/patches
+
+BOARD=fl2440
+PATCH_SUFFIX=${BOARD}.patch
+
+function do_clean()
+{
+    if [ -f .config ] ; then
+        set -x
+        cp .config .cfg-${BOARD}
+        set +x
+    fi
+
+    #echo "WARNNING: Maybe need input sudo passwd here: "
+    bash build.sh clean
+}
+
+if [ $# != 1 ] ; then
+    echo "Usage: $0 [src_path]"
+    printf "\nExample: \n"
+    echo "$0 linux-3.0"
+
+    exit ;
+fi
+
+
+SRC=`basename $1`
+
+if [ ! -d ${SRC} ] ; then
+    printf "\nERROR: ${SRC} source code not exist, exit now\n\n"
+    exit
+fi
+
+if [ ! -f ${PACK_PATH}/${SRC}.tar.bz2 ] ; then
+    printf "\nERROR: ${SRC}.tar.bz2 packet not exist, exit now\n\n"
+    exit
+fi
+
+cd ${PROJ_PATH}
+
+cd ${SRC}
+do_clean
+cd -
+
+# rename new source code
+mv ${SRC} ${SRC}-${BOARD}
+
+# decompress orignal soruce code packet
+tar -xjf ${PACK_PATH}/${SRC}.tar.bz2
+
+# generate patch file 
+if [[ $SRC =~ linux ]] ; then
+    diff -Nuar -x ".gitignore" ${SRC} ${SRC}-${BOARD} > ${SRC}-${PATCH_SUFFIX}
+else
+    diff -Nuar ${SRC} ${SRC}-${BOARD}  > ${SRC}-${PATCH_SUFFIX}
+fi
+
+# remove orignal soruce code
+rm -rf ${SRC}
+
+# recover new source code
+mv ${SRC}-${BOARD} ${SRC} 
+
diff --git a/linux-bsp/patches/linux-3.0-fl2440.patch b/linux-bsp/patches/linux-3.0-fl2440.patch
new file mode 100644
index 0000000..7721faa
--- /dev/null
+++ b/linux-bsp/patches/linux-3.0-fl2440.patch
@@ -0,0 +1,4153 @@
+diff -Nuar -x .gitignore linux-3.0/arch/arm/mach-s3c2440/mach-smdk2440.c linux-3.0-fl2440/arch/arm/mach-s3c2440/mach-smdk2440.c
+--- linux-3.0/arch/arm/mach-s3c2440/mach-smdk2440.c	2011-07-22 10:17:23.000000000 +0800
++++ linux-3.0-fl2440/arch/arm/mach-s3c2440/mach-smdk2440.c	2020-01-09 16:54:31.213380202 +0800
+@@ -23,6 +23,14 @@
+ #include <linux/platform_device.h>
+ #include <linux/io.h>
+ 
++/*  add by guowenxue for norflash  */
++#include <linux/gpio_keys.h>
++#include <linux/input.h>
++#include <linux/mtd/physmap.h>
++#include <linux/mtd/mtd.h>
++#include <linux/mtd/partitions.h>
++#include <linux/mmc/host.h>
++
+ #include <asm/mach/arch.h>
+ #include <asm/mach/map.h>
+ #include <asm/mach/irq.h>
+@@ -44,6 +52,13 @@
+ #include <plat/clock.h>
+ #include <plat/devs.h>
+ #include <plat/cpu.h>
++#include <plat/mci.h>        /* Add by guowenxue to support MMC detect, 2017.5.4 */
++#include <plat/udc.h>        /* Add by guowenxue to support USB device gadget, 2017.5.4 */
++#include <plat/ts.h>         /* Add by guowenxue to support Touch screen, 2011.09.06*/
++#include <mach/regs-clock.h> /* Add by guowenxue 2012.07.15, for usb_s3c2440_init() */
++#include <linux/i2c.h>       /* Add by guowenxue 2012.10.22, for AT24C02 driver */
++#include <linux/i2c/at24.h>  /* Add by guowenxue 2012.10.22, for AT24C02 driver */
++#include <linux/delay.h>
+ 
+ #include <plat/common-smdk.h>
+ 
+@@ -102,6 +117,26 @@
+ 	}
+ };
+ 
++/*  USB device UDC support add by guowenxue 2017.5.4 */
++static struct s3c2410_udc_mach_info smdk2440_udc_cfg __initdata = {
++        .pullup_pin = S3C2410_GPG(9),
++};
++
++/*  MMC/SD support add by guowenxue 2017.5.4 */
++static struct s3c24xx_mci_pdata smdk2440_mmc_cfg __initdata = {
++    .gpio_detect   = S3C2410_GPG(10),
++    .gpio_wprotect = S3C2410_GPH(8),
++    .set_power     = NULL,
++    .ocr_avail     = MMC_VDD_32_33|MMC_VDD_33_34,
++};
++
++/*Touch Screen driver info add by guowenxue 2011.09.04 */
++static struct s3c2410_ts_mach_info smdk2440_ts_cfg __initdata = {
++    .delay = 10000,
++    .presc = 49,
++    .oversampling_shift = 2,
++};
++
+ /* LCD driver info */
+ 
+ static struct s3c2410fb_display smdk2440_lcd_cfg __initdata = {
+@@ -114,19 +149,34 @@
+ 
+ 	.type		= S3C2410_LCDCON1_TFT,
+ 
+-	.width		= 240,
+-	.height		= 320,
++	.width		= 320,
++	.height		= 240,
+ 
+-	.pixclock	= 166667, /* HCLK 60 MHz, divisor 10 */
+-	.xres		= 240,
+-	.yres		= 320,
+-	.bpp		= 16,
+-	.left_margin	= 20,
+-	.right_margin	= 8,
+-	.hsync_len	= 4,
+-	.upper_margin	= 8,
+-	.lower_margin	= 7,
+-	.vsync_len	= 4,
++    /*Set value from LCD datasheet, pixclock set refer to 
++     *document linux-3.0/Documentation/fb/framebuffer.txt */
++#if 0 /* For 3.5" TFT-LCD (WXCAT35-TG3#001) */
++	.pixclock	= 156250, /* Dclk-Period          =>1000000/Dclk=1000000/6.4*/
++	.xres		= 320,    /* Hsync Display Period =>Thd  320*/
++	.yres		= 240,    /* Vsync Display Period =>Tvd  240*/
++	.bpp		= 16,     /* 16 bpp*/
++	.left_margin	= 38, /* Hsync Front-Porch    =>Thf 38*/
++	.right_margin	= 20, /* Hsync Back-Porch     =>Thb 20*/
++	.hsync_len	= 30,     /* Hsync Pulse Width    =>Thp 30*/
++	.upper_margin	= 15, /* Vsync Front-Porch    =>Tvf 15*/
++	.lower_margin	= 12, /* Vsync Back-Porch     =>Tvb 12*/
++	.vsync_len	= 3,      /* Vsync Pulse Width    =>Tvp 3*/
++#else  /* For 4.3" TFT-LCD (WXCAT43-TG3#001) */
++	.pixclock	= 111111, /* Dclk-Period          =>1000000/Dclk=1000000/9*/
++	.xres		= 480,    /* Hsync Display Period =>Thd  480*/
++	.yres		= 272,    /* Vsync Display Period =>Tvd  272*/
++	.bpp		= 16,     /* 16 bpp*/
++	.left_margin	= 38, /* Hsync Front-Porch    =>Thf 38*/
++	.right_margin	= 20, /* Hsync Back-Porch     =>Thb 2*/
++	.hsync_len	= 30,     /* Hsync Pulse Width    =>Thp 41*/
++	.upper_margin	= 15, /* Vsync Front-Porch    =>Tvf 2*/
++	.lower_margin	= 12, /* Vsync Back-Porch     =>Tvb 2*/
++	.vsync_len	= 3,      /* Vsync Pulse Width    =>Tvp 10*/
++#endif
+ };
+ 
+ static struct s3c2410fb_mach_info smdk2440_fb_info __initdata = {
+@@ -146,7 +196,113 @@
+ 	.gpdup_mask	= 0xffffffff,
+ #endif
+ 
+-	.lpcsel		= ((0xCE6) & ~7) | 1<<4,
++	.lpcsel		= ((0xCE6) & ~7) | 1<<1,
++
++};
++
++
++/* S3C2440 GPIO buttons add by guowenxue, 2013.05.29 */
++#ifdef CONFIG_KEYBOARD_GPIO 
++static struct gpio_keys_button s3c2440_buttons[] = {
++    {
++        .gpio       = S3C2410_GPF(0),       /* K1 */
++        .code       = BTN_1,
++        .desc       = "Button 1",
++        .active_low = 1,
++    },
++    {
++        .gpio       = S3C2410_GPF(2),       /* K2 */
++        .code       = BTN_2,
++        .desc       = "Button 2",
++        .active_low = 1,
++    },
++    {
++        .gpio       = S3C2410_GPF(3),       /* K3 */
++        .code       = BTN_3,
++        .desc       = "Button 3",
++        .active_low = 1,
++    },
++    {
++        .gpio       = S3C2410_GPF(4),       /* K4 */
++        .code       = BTN_4,
++        .desc       = "Button 4",
++        .active_low = 1,
++    },
++};
++
++static struct gpio_keys_platform_data s3c2440_button_data = {
++    .buttons    = s3c2440_buttons,
++    .nbuttons   = ARRAY_SIZE(s3c2440_buttons),
++}; 
++
++static struct platform_device s3c2440_button_device = {
++    .name       = "gpio-keys",
++    .id     = -1,
++    .dev        = {
++        .platform_data  = &s3c2440_button_data,
++    }
++};
++#endif
++
++
++/* 
++ * I2C devices, add by guowenxue
++ */
++
++static struct at24_platform_data at24c02 = {
++    .byte_len   = SZ_2K / 8,
++    .page_size  = 8, 
++    .flags      = 0,
++};
++
++static struct i2c_board_info __initdata smdk2440_i2c_devs[] = {
++    {   
++        I2C_BOARD_INFO("24c02", 0x50),
++        .platform_data = &at24c02,
++    },
++    /*  more devices can be added using expansion connectors */
++};
++
++/* Add 4MiB norflash JS28F320 on fl2440 by guowenxue 2012.12.09 */
++#define NORFLASH_BASE   S3C2410_CS1
++#define NORFLASH_SIZE   SZ_4M
++
++static struct mtd_partition __initdata norflash_partitions[] = {
++    {
++        .name   = "norflash bootloader",
++        .offset = 0,
++        .size   = SZ_512K,
++    },
++    {
++        .name   = "norflash system",
++        .offset = MTDPART_OFS_NXTBLK,
++        .size   = MTDPART_SIZ_FULL,
++    },
++};
++
++static struct physmap_flash_data norflash_data = {
++    .width      = 2,
++    .parts      = norflash_partitions,
++    .nr_parts   = ARRAY_SIZE(norflash_partitions),
++};
++
++
++static struct resource norflash_resources[] = {
++    {
++        .start  = NORFLASH_BASE,
++        .end    = NORFLASH_BASE + NORFLASH_SIZE - 1,
++        .flags  = IORESOURCE_MEM,
++    }
++};
++
++static struct platform_device s3c_device_norflash = {
++    .name       = "physmap-flash",
++    .id         = 0,
++    .dev        = {
++        .platform_data = &norflash_data,
++    },
++    .resource   = norflash_resources,
++    .num_resources = ARRAY_SIZE(norflash_resources),
+ };
+ 
+ static struct platform_device *smdk2440_devices[] __initdata = {
+@@ -155,19 +311,51 @@
+ 	&s3c_device_wdt,
+ 	&s3c_device_i2c0,
+ 	&s3c_device_iis,
++    &s3c_device_usbgadget, /* Add USB slave gadget by guowenxue, 2017.5.4 */
++    &s3c_device_norflash, /* Add norflash driver by guowenxue, 2012.12.09 */
++    &uda1341_codec,     /* Add uda1341 driver by guowenxue, 2012.03.30 */
++    &s3c24xx_uda134x,   /* Add uda1341 driver by guowenxue, 2012.03.30 */
++    &samsung_asoc_dma,  /* Add uda1341 driver by guowenxue, 2012.03.30 */
++    &s3c_device_dm9000, /* Add DM9000 ethernet car driver by guowenxue, 2011.08.30*/
++    &s3c_device_sdi,    /* Add SD card driver by guowenxue, 2011.09.06*/
++    &s3c_device_rtc,    /* Add RTC driver by guowenxue, 2011.09.06*/
++    &s3c_device_adc,    /* Add Touch Screen driver by guowenxue, 2011.09.06*/
++    &s3c_device_ts,     /* Add Touch Screen driver by guowenxue, 2011.09.06*/
++#ifdef CONFIG_KEYBOARD_GPIO /* Add Button driver by guowenxue, 2013.05.29*/
++    &s3c2440_button_device
++#endif
+ };
+ 
++/* Add by guowenxue 2012.07.15, fix device descriptor read/64, error -62 bug, value refer to datasheet P255 */ 
++int usb_s3c2440_init(void)
++{
++    /* Input Frequency is 12.0000MHz, and MDEV=0x38 PDIV=2 SDIV=2, so output frequency 48.00MHz */
++    unsigned long upllvalue = (0x38<<12)|(0x02<<4)|(0x02); 
++    while (upllvalue != __raw_readl(S3C2410_UPLLCON)) 
++    { 
++        __raw_writel(upllvalue, S3C2410_UPLLCON); 
++        mdelay(1); 
++    }
++
++    return 0;
++}
++
+ static void __init smdk2440_map_io(void)
+ {
+ 	s3c24xx_init_io(smdk2440_iodesc, ARRAY_SIZE(smdk2440_iodesc));
+-	s3c24xx_init_clocks(16934400);
++	s3c24xx_init_clocks(12000000); /*Modify by guowenxue, 2011.08.30*/
+ 	s3c24xx_init_uarts(smdk2440_uartcfgs, ARRAY_SIZE(smdk2440_uartcfgs));
++    usb_s3c2440_init(); /* Add by guowenxue, 2012.07.15 */
+ }
+ 
+ static void __init smdk2440_machine_init(void)
+ {
++    s3c24xx_udc_set_platdata(&smdk2440_udc_cfg); /* add USB gadget UDC by guowenxue, 2017.5.4 */
++    s3c24xx_mci_set_platdata(&smdk2440_mmc_cfg); /*  add USB gadget UDC by guowenxue, 2017.5.4 */
+ 	s3c24xx_fb_set_platdata(&smdk2440_fb_info);
++    s3c24xx_ts_set_platdata(&smdk2440_ts_cfg); /*Add Touch Screen info by guowenxue, 2011.09.06*/
+ 	s3c_i2c0_set_platdata(NULL);
++    i2c_register_board_info(0, smdk2440_i2c_devs, ARRAY_SIZE(smdk2440_i2c_devs));
+ 
+ 	platform_add_devices(smdk2440_devices, ARRAY_SIZE(smdk2440_devices));
+ 	smdk_machine_init();
+diff -Nuar -x .gitignore linux-3.0/arch/arm/plat-s3c24xx/common-smdk.c linux-3.0-fl2440/arch/arm/plat-s3c24xx/common-smdk.c
+--- linux-3.0/arch/arm/plat-s3c24xx/common-smdk.c	2011-07-22 10:17:23.000000000 +0800
++++ linux-3.0-fl2440/arch/arm/plat-s3c24xx/common-smdk.c	2020-01-09 16:54:31.213380202 +0800
+@@ -48,107 +48,98 @@
+ 
+ /* LED devices */
+ 
+-static struct s3c24xx_led_platdata smdk_pdata_led4 = {
+-	.gpio		= S3C2410_GPF(4),
++static struct s3c24xx_led_platdata smdk_pdata_led0 = {
++	.gpio		= S3C2410_GPB(5),
+ 	.flags		= S3C24XX_LEDF_ACTLOW | S3C24XX_LEDF_TRISTATE,
+-	.name		= "led4",
+-	.def_trigger	= "timer",
++	.name		= "led0",
++	.def_trigger	= "heartbeat",
+ };
+ 
+-static struct s3c24xx_led_platdata smdk_pdata_led5 = {
+-	.gpio		= S3C2410_GPF(5),
++static struct s3c24xx_led_platdata smdk_pdata_led1 = {
++	.gpio		= S3C2410_GPB(6),
+ 	.flags		= S3C24XX_LEDF_ACTLOW | S3C24XX_LEDF_TRISTATE,
+-	.name		= "led5",
+-	.def_trigger	= "nand-disk",
++	.name		= "led1",
++	//.def_trigger	= "nand-disk",
+ };
+ 
+-static struct s3c24xx_led_platdata smdk_pdata_led6 = {
+-	.gpio		= S3C2410_GPF(6),
++static struct s3c24xx_led_platdata smdk_pdata_led2 = {
++	.gpio		= S3C2410_GPB(8),
+ 	.flags		= S3C24XX_LEDF_ACTLOW | S3C24XX_LEDF_TRISTATE,
+-	.name		= "led6",
++	.name		= "led2",
++	//.def_trigger	= "timer",
+ };
+ 
+-static struct s3c24xx_led_platdata smdk_pdata_led7 = {
+-	.gpio		= S3C2410_GPF(7),
++static struct s3c24xx_led_platdata smdk_pdata_led3 = {
++	.gpio		= S3C2410_GPB(10),
+ 	.flags		= S3C24XX_LEDF_ACTLOW | S3C24XX_LEDF_TRISTATE,
+-	.name		= "led7",
++	.name		= "led3",
+ };
+ 
+-static struct platform_device smdk_led4 = {
++static struct platform_device smdk_led0 = {
+ 	.name		= "s3c24xx_led",
+ 	.id		= 0,
+ 	.dev		= {
+-		.platform_data = &smdk_pdata_led4,
++		.platform_data = &smdk_pdata_led0,
+ 	},
+ };
+ 
+-static struct platform_device smdk_led5 = {
++static struct platform_device smdk_led1 = {
+ 	.name		= "s3c24xx_led",
+ 	.id		= 1,
+ 	.dev		= {
+-		.platform_data = &smdk_pdata_led5,
++		.platform_data = &smdk_pdata_led1,
+ 	},
+ };
+ 
+-static struct platform_device smdk_led6 = {
++static struct platform_device smdk_led2 = {
+ 	.name		= "s3c24xx_led",
+ 	.id		= 2,
+ 	.dev		= {
+-		.platform_data = &smdk_pdata_led6,
++		.platform_data = &smdk_pdata_led2,
+ 	},
+ };
+ 
+-static struct platform_device smdk_led7 = {
++static struct platform_device smdk_led3 = {
+ 	.name		= "s3c24xx_led",
+ 	.id		= 3,
+ 	.dev		= {
+-		.platform_data = &smdk_pdata_led7,
++		.platform_data = &smdk_pdata_led3,
+ 	},
+ };
+ 
+-/* NAND parititon from 2.4.18-swl5 */
++/* NAND parititon from 2.4.18-swl5, modify by guowenxue 2015.11.13, K9F2G08,256MiB */
+ 
+ static struct mtd_partition smdk_default_nand_part[] = {
+-	[0] = {
+-		.name	= "Boot Agent",
+-		.size	= SZ_16K,
+-		.offset	= 0,
+-	},
+-	[1] = {
+-		.name	= "S3C2410 flash partition 1",
+-		.offset = 0,
+-		.size	= SZ_2M,
+-	},
+-	[2] = {
+-		.name	= "S3C2410 flash partition 2",
+-		.offset = SZ_4M,
+-		.size	= SZ_4M,
+-	},
+-	[3] = {
+-		.name	= "S3C2410 flash partition 3",
+-		.offset	= SZ_8M,
+-		.size	= SZ_2M,
+-	},
+-	[4] = {
+-		.name	= "S3C2410 flash partition 4",
+-		.offset = SZ_1M * 10,
+-		.size	= SZ_4M,
+-	},
+-	[5] = {
+-		.name	= "S3C2410 flash partition 5",
+-		.offset	= SZ_1M * 14,
+-		.size	= SZ_1M * 10,
+-	},
+-	[6] = {
+-		.name	= "S3C2410 flash partition 6",
+-		.offset	= SZ_1M * 24,
+-		.size	= SZ_1M * 24,
+-	},
+-	[7] = {
+-		.name	= "S3C2410 flash partition 7",
+-		.offset = SZ_1M * 48,
+-		.size	= MTDPART_SIZ_FULL,
+-	}
++        [0] = {
++                .name           = "mtdblock0 u-boot 1MB",
++                .offset         = 0,
++                .size           = SZ_1M*1,  /* 0x0000000 ~ 0x0100000 */
++        },
++        [1] = {
++                .name           = "mtdblock1 kernel 15MB",
++                .offset         = MTDPART_OFS_NXTBLK,
++                .size           = SZ_1M*15, /* 0x0100000 ~ 0X1000000 */
++        },
++        [2] = {
++                .name           = "mtdblock2 rootfs 40MB",
++                .offset         = MTDPART_OFS_NXTBLK,
++                .size           = SZ_1M*40, 
++        },
++        [3] = {
++                .name           = "mtdblock3 apps 80MB",
++                .offset         = MTDPART_OFS_NXTBLK,
++                .size           = SZ_1M*80, 
++        },
++        [4] = {
++                .name           = "mtdblock4 data 80MB",
++                .offset         = MTDPART_OFS_NXTBLK,
++                .size           = SZ_1M*80, 
++        },
++        [5] = {
++                .name           = "mtdblock5 backup 40MB",
++                .offset         = MTDPART_OFS_NXTBLK,
++                .size           = SZ_1M*40, 
++        },
+ };
+ 
+ static struct s3c2410_nand_set smdk_nand_sets[] = {
+@@ -176,10 +167,10 @@
+ 
+ static struct platform_device __initdata *smdk_devs[] = {
+ 	&s3c_device_nand,
+-	&smdk_led4,
+-	&smdk_led5,
+-	&smdk_led6,
+-	&smdk_led7,
++	&smdk_led0,
++	&smdk_led1,
++	&smdk_led2,
++	&smdk_led3,
+ };
+ 
+ void __init smdk_machine_init(void)
+diff -Nuar -x .gitignore linux-3.0/arch/arm/plat-s3c24xx/devs.c linux-3.0-fl2440/arch/arm/plat-s3c24xx/devs.c
+--- linux-3.0/arch/arm/plat-s3c24xx/devs.c	2011-07-22 10:17:23.000000000 +0800
++++ linux-3.0-fl2440/arch/arm/plat-s3c24xx/devs.c	2020-01-09 16:54:31.213380202 +0800
+@@ -299,6 +299,66 @@
+ 
+ EXPORT_SYMBOL(s3c_device_iis);
+ 
++#ifdef CONFIG_SND_SOC_SAMSUNG_S3C24XX_UDA134X  /* UDA1341 add by guowenxue, 2012.03.30 */
++#include <sound/s3c24xx_uda134x.h> /* Add by guowenxue, 2012.03.30 */
++#include <mach/gpio-nrs.h>
++struct s3c24xx_uda134x_platform_data s3c24xx_uda134x_data = { 
++    .l3_clk = S3C2410_GPB(4), 
++    .l3_data = S3C2410_GPB(3), 
++    .l3_mode = S3C2410_GPB(2), 
++    .model = UDA134X_UDA1341,
++};
++
++struct platform_device s3c24xx_uda134x = { 
++    .name = "s3c24xx_uda134x", 
++    .dev = { 
++        .platform_data    = &s3c24xx_uda134x_data, 
++    }
++};
++EXPORT_SYMBOL(s3c24xx_uda134x);
++
++struct platform_device uda1341_codec = { 
++    .name = "uda134x-codec", 
++    .id = -1,
++};
++#endif
++
++#ifdef CONFIG_DM9000 /*DM9000 network device support add by guowenxue 2011.08.30*/
++#include <linux/dm9000.h> 
++static struct resource s3c_dm9000_resource[] = {
++   [0] = {
++      .start = S3C2410_CS4 + 0x300,
++      .end   = S3C2410_CS4 + 0x300 + 0x3,
++      .flags = IORESOURCE_MEM
++   },
++   [1]={
++      .start = S3C2410_CS4 + 0x300 + 0x4, //CMD pin is A2
++      .end = S3C2410_CS4 + 0x300 + 0x4 + 0x7c,
++      .flags = IORESOURCE_MEM
++   },
++   [2] = {
++      .start = IRQ_EINT7,
++      .end   = IRQ_EINT7,
++      .flags = IORESOURCE_IRQ
++   },
++};
++
++static struct dm9000_plat_data s3c_device_dm9000_platdata = {
++   .flags= DM9000_PLATF_16BITONLY,
++};
++
++struct platform_device s3c_device_dm9000 = {
++   .name= "dm9000",
++   .id= 0,
++   .num_resources= ARRAY_SIZE(s3c_dm9000_resource),
++   .resource= s3c_dm9000_resource,
++   .dev= {
++       .platform_data = &s3c_device_dm9000_platdata,
++   }
++};
++#endif
++
++
+ /* RTC */
+ 
+ static struct resource s3c_rtc_resource[] = {
+diff -Nuar -x .gitignore linux-3.0/arch/arm/plat-samsung/include/plat/devs.h linux-3.0-fl2440/arch/arm/plat-samsung/include/plat/devs.h
+--- linux-3.0/arch/arm/plat-samsung/include/plat/devs.h	2011-07-22 10:17:23.000000000 +0800
++++ linux-3.0-fl2440/arch/arm/plat-samsung/include/plat/devs.h	2020-01-09 16:54:31.273380204 +0800
+@@ -93,6 +93,10 @@
+ extern struct platform_device s3c_device_usb_hsudc;
+ extern struct platform_device s3c_device_usb_hsotg;
+ 
++extern struct platform_device s3c_device_dm9000;  /*Add by guowenxue, 2011.08.30*/
++extern struct platform_device s3c24xx_uda134x;    /*Add by guowenxue, 2012.03.30*/
++extern struct platform_device uda1341_codec;      /*Add by guowenxue, 2012.03.30*/
++
+ extern struct platform_device s5pv210_device_ac97;
+ extern struct platform_device s5pv210_device_pcm0;
+ extern struct platform_device s5pv210_device_pcm1;
+diff -Nuar -x .gitignore linux-3.0/arch/arm/tools/mach-types linux-3.0-fl2440/arch/arm/tools/mach-types
+--- linux-3.0/arch/arm/tools/mach-types	2011-07-22 10:17:23.000000000 +0800
++++ linux-3.0-fl2440/arch/arm/tools/mach-types	2020-01-09 16:54:31.273380204 +0800
+@@ -85,7 +85,8 @@
+ bast			ARCH_BAST		BAST			331
+ h1940			ARCH_H1940		H1940			347
+ enp2611			ARCH_ENP2611		ENP2611			356
+-s3c2440			ARCH_S3C2440		S3C2440			362
++#Changed by guowenxue, 2011.08.30
++s3c2440			ARCH_S3C2440		S3C2440			1999
+ gumstix			ARCH_GUMSTIX		GUMSTIX			373
+ omap_h2			MACH_OMAP_H2		OMAP_H2			382
+ e740			MACH_E740		E740			384
+@@ -356,7 +357,8 @@
+ snapper_9260		MACH_SNAPPER_9260	SNAPPER_9260		1987
+ dsm320			MACH_DSM320		DSM320			1988
+ exeda			MACH_EXEDA		EXEDA			1994
+-mini2440		MACH_MINI2440		MINI2440		1999
++#Changed by guowenxue, 2011.08.30
++mini2440		MACH_MINI2440		MINI2440		362
+ colibri300		MACH_COLIBRI300		COLIBRI300		2000
+ linkstation_ls_hgl	MACH_LINKSTATION_LS_HGL	LINKSTATION_LS_HGL	2005
+ cpuat9g20		MACH_CPUAT9G20		CPUAT9G20		2031
+diff -Nuar -x .gitignore linux-3.0/build.sh linux-3.0-fl2440/build.sh
+--- linux-3.0/build.sh	1970-01-01 08:00:00.000000000 +0800
++++ linux-3.0-fl2440/build.sh	2020-01-09 17:27:02.941417641 +0800
+@@ -0,0 +1,82 @@
++#!/bin/bash
++
++BOARD=fl2440
++TFTP_PATH=/tftp
++IMGS_PATH=../images
++IMG_FILES=linuxrom-${BOARD}.bin
++
++CROSSTOOL=/opt/xtools/arm920t/bin/arm-linux-
++
++JOBS=`cat /proc/cpuinfo |grep "processor"|wc -l`
++
++set -e
++
++function clean_initramfs()
++{
++    cd usr
++    rm -f .??*
++    rm -f initramfs_data.o initramfs_data.cpio built-in.o
++    cd -
++}
++
++function do_clean()
++{
++    #clean_initramfs
++    rm -f ${IMG_FILES}
++    rm -f cscope* tags
++    make CROSS_COMPILE=${CROSSTOOL} distclean
++}
++
++function do_build()
++{
++    clean_initramfs 
++
++    if [ ! -f .config ] ; then
++       cp .cfg-${BOARD} .config 
++    fi
++
++    rm -f arch/arm/boot/dts/*.dtb
++
++    sed -i "s|^\<ARCH\>.*|ARCH\t\t\t?=  arm|g" Makefile 
++    sed -i "s|^CROSS_COMPILE.*|CROSS_COMPILE\t?=  ${CROSSTOOL}|g" Makefile 
++
++    make -j${JOBS} 
++
++    if [ ! -f ${IMG_FILES} ] ; then
++       mv linuxrom-*.bin ${IMG_FILES}
++    fi
++}
++
++function do_install()
++{
++    if [ -d $TFTP_PATH ] ;then 
++        echo "cp ${IMG_FILES} $TFTP_PATH"
++        cp ${IMG_FILES} $TFTP_PATH
++    fi
++
++    if [ -d ${IMGS_PATH} ] ; then
++        echo "cp ${IMG_FILES} $IMGS_PATH"
++        cp ${IMG_FILES} $IMGS_PATH
++    fi
++}
++
++if [ "y${INITRAMFS}" == "yYES" ] ; then
++    if [ `id -u` != 0 ] ; then
++        printf "\nERROR: kernel build with initramfs support must use root or sudo\n\n"
++        exit;
++    fi
++fi
++
++
++if [ "$1" == "clean" ] ; then 
++
++    do_clean
++    exit 0;
++
++fi
++
++do_build
++
++do_install
++
++
+diff -Nuar -x .gitignore linux-3.0/.cfg-fl2440 linux-3.0-fl2440/.cfg-fl2440
+--- linux-3.0/.cfg-fl2440	1970-01-01 08:00:00.000000000 +0800
++++ linux-3.0-fl2440/.cfg-fl2440	2020-01-09 17:09:56.601397954 +0800
+@@ -0,0 +1,2407 @@
++#
++# Automatically generated make config: don't edit
++# Linux/arm 3.0.0 Kernel Configuration
++#
++CONFIG_ARM=y
++CONFIG_HAVE_PWM=y
++CONFIG_SYS_SUPPORTS_APM_EMULATION=y
++CONFIG_GENERIC_GPIO=y
++CONFIG_ARCH_USES_GETTIMEOFFSET=y
++CONFIG_KTIME_SCALAR=y
++CONFIG_HAVE_PROC_CPU=y
++CONFIG_NO_IOPORT=y
++CONFIG_STACKTRACE_SUPPORT=y
++CONFIG_HAVE_LATENCYTOP_SUPPORT=y
++CONFIG_LOCKDEP_SUPPORT=y
++CONFIG_TRACE_IRQFLAGS_SUPPORT=y
++CONFIG_HARDIRQS_SW_RESEND=y
++CONFIG_GENERIC_IRQ_PROBE=y
++CONFIG_RWSEM_GENERIC_SPINLOCK=y
++CONFIG_ARCH_HAS_CPUFREQ=y
++CONFIG_ARCH_HAS_CPU_IDLE_WAIT=y
++CONFIG_GENERIC_HWEIGHT=y
++CONFIG_GENERIC_CALIBRATE_DELAY=y
++CONFIG_NEED_DMA_MAP_STATE=y
++CONFIG_VECTORS_BASE=0xffff0000
++# CONFIG_ARM_PATCH_PHYS_VIRT is not set
++CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
++CONFIG_HAVE_IRQ_WORK=y
++
++#
++# General setup
++#
++CONFIG_EXPERIMENTAL=y
++CONFIG_BROKEN_ON_SMP=y
++CONFIG_INIT_ENV_ARG_LIMIT=32
++CONFIG_CROSS_COMPILE=""
++CONFIG_LOCALVERSION=""
++# CONFIG_LOCALVERSION_AUTO is not set
++CONFIG_HAVE_KERNEL_GZIP=y
++CONFIG_HAVE_KERNEL_LZMA=y
++CONFIG_HAVE_KERNEL_LZO=y
++CONFIG_KERNEL_GZIP=y
++# CONFIG_KERNEL_LZMA is not set
++# CONFIG_KERNEL_LZO is not set
++CONFIG_DEFAULT_HOSTNAME="(none)"
++# CONFIG_SWAP is not set
++CONFIG_SYSVIPC=y
++CONFIG_SYSVIPC_SYSCTL=y
++# CONFIG_POSIX_MQUEUE is not set
++# CONFIG_BSD_PROCESS_ACCT is not set
++# CONFIG_FHANDLE is not set
++# CONFIG_TASKSTATS is not set
++# CONFIG_AUDIT is not set
++CONFIG_HAVE_GENERIC_HARDIRQS=y
++
++#
++# IRQ subsystem
++#
++CONFIG_GENERIC_HARDIRQS=y
++CONFIG_HAVE_SPARSE_IRQ=y
++CONFIG_GENERIC_IRQ_SHOW=y
++CONFIG_GENERIC_IRQ_CHIP=y
++# CONFIG_SPARSE_IRQ is not set
++
++#
++# RCU Subsystem
++#
++CONFIG_TINY_RCU=y
++# CONFIG_PREEMPT_RCU is not set
++# CONFIG_RCU_TRACE is not set
++# CONFIG_TREE_RCU_TRACE is not set
++CONFIG_IKCONFIG=y
++CONFIG_IKCONFIG_PROC=y
++CONFIG_LOG_BUF_SHIFT=16
++# CONFIG_CGROUPS is not set
++# CONFIG_NAMESPACES is not set
++# CONFIG_SCHED_AUTOGROUP is not set
++# CONFIG_SYSFS_DEPRECATED is not set
++# CONFIG_RELAY is not set
++# CONFIG_BLK_DEV_INITRD is not set
++CONFIG_CC_OPTIMIZE_FOR_SIZE=y
++CONFIG_SYSCTL=y
++CONFIG_ANON_INODES=y
++CONFIG_EXPERT=y
++CONFIG_UID16=y
++CONFIG_SYSCTL_SYSCALL=y
++CONFIG_KALLSYMS=y
++CONFIG_HOTPLUG=y
++CONFIG_PRINTK=y
++CONFIG_BUG=y
++CONFIG_ELF_CORE=y
++CONFIG_BASE_FULL=y
++CONFIG_FUTEX=y
++CONFIG_EPOLL=y
++CONFIG_SIGNALFD=y
++CONFIG_TIMERFD=y
++CONFIG_EVENTFD=y
++CONFIG_SHMEM=y
++CONFIG_AIO=y
++CONFIG_EMBEDDED=y
++CONFIG_HAVE_PERF_EVENTS=y
++CONFIG_PERF_USE_VMALLOC=y
++
++#
++# Kernel Performance Events And Counters
++#
++# CONFIG_PERF_EVENTS is not set
++# CONFIG_PERF_COUNTERS is not set
++CONFIG_VM_EVENT_COUNTERS=y
++CONFIG_COMPAT_BRK=y
++CONFIG_SLAB=y
++# CONFIG_SLUB is not set
++# CONFIG_SLOB is not set
++# CONFIG_PROFILING is not set
++CONFIG_HAVE_OPROFILE=y
++# CONFIG_KPROBES is not set
++CONFIG_HAVE_KPROBES=y
++CONFIG_HAVE_KRETPROBES=y
++CONFIG_HAVE_REGS_AND_STACK_ACCESS_API=y
++CONFIG_HAVE_CLK=y
++CONFIG_HAVE_DMA_API_DEBUG=y
++
++#
++# GCOV-based kernel profiling
++#
++CONFIG_HAVE_GENERIC_DMA_COHERENT=y
++CONFIG_SLABINFO=y
++CONFIG_RT_MUTEXES=y
++CONFIG_BASE_SMALL=0
++CONFIG_MODULES=y
++CONFIG_MODULE_FORCE_LOAD=y
++CONFIG_MODULE_UNLOAD=y
++# CONFIG_MODULE_FORCE_UNLOAD is not set
++# CONFIG_MODVERSIONS is not set
++# CONFIG_MODULE_SRCVERSION_ALL is not set
++CONFIG_BLOCK=y
++# CONFIG_LBDAF is not set
++# CONFIG_BLK_DEV_BSG is not set
++# CONFIG_BLK_DEV_INTEGRITY is not set
++
++#
++# IO Schedulers
++#
++CONFIG_IOSCHED_NOOP=y
++CONFIG_IOSCHED_DEADLINE=y
++CONFIG_IOSCHED_CFQ=y
++# CONFIG_DEFAULT_DEADLINE is not set
++CONFIG_DEFAULT_CFQ=y
++# CONFIG_DEFAULT_NOOP is not set
++CONFIG_DEFAULT_IOSCHED="cfq"
++# CONFIG_INLINE_SPIN_TRYLOCK is not set
++# CONFIG_INLINE_SPIN_TRYLOCK_BH is not set
++# CONFIG_INLINE_SPIN_LOCK is not set
++# CONFIG_INLINE_SPIN_LOCK_BH is not set
++# CONFIG_INLINE_SPIN_LOCK_IRQ is not set
++# CONFIG_INLINE_SPIN_LOCK_IRQSAVE is not set
++CONFIG_INLINE_SPIN_UNLOCK=y
++# CONFIG_INLINE_SPIN_UNLOCK_BH is not set
++CONFIG_INLINE_SPIN_UNLOCK_IRQ=y
++# CONFIG_INLINE_SPIN_UNLOCK_IRQRESTORE is not set
++# CONFIG_INLINE_READ_TRYLOCK is not set
++# CONFIG_INLINE_READ_LOCK is not set
++# CONFIG_INLINE_READ_LOCK_BH is not set
++# CONFIG_INLINE_READ_LOCK_IRQ is not set
++# CONFIG_INLINE_READ_LOCK_IRQSAVE is not set
++CONFIG_INLINE_READ_UNLOCK=y
++# CONFIG_INLINE_READ_UNLOCK_BH is not set
++CONFIG_INLINE_READ_UNLOCK_IRQ=y
++# CONFIG_INLINE_READ_UNLOCK_IRQRESTORE is not set
++# CONFIG_INLINE_WRITE_TRYLOCK is not set
++# CONFIG_INLINE_WRITE_LOCK is not set
++# CONFIG_INLINE_WRITE_LOCK_BH is not set
++# CONFIG_INLINE_WRITE_LOCK_IRQ is not set
++# CONFIG_INLINE_WRITE_LOCK_IRQSAVE is not set
++CONFIG_INLINE_WRITE_UNLOCK=y
++# CONFIG_INLINE_WRITE_UNLOCK_BH is not set
++CONFIG_INLINE_WRITE_UNLOCK_IRQ=y
++# CONFIG_INLINE_WRITE_UNLOCK_IRQRESTORE is not set
++# CONFIG_MUTEX_SPIN_ON_OWNER is not set
++CONFIG_FREEZER=y
++
++#
++# System Type
++#
++CONFIG_MMU=y
++# CONFIG_ARCH_INTEGRATOR is not set
++# CONFIG_ARCH_REALVIEW is not set
++# CONFIG_ARCH_VERSATILE is not set
++# CONFIG_ARCH_VEXPRESS is not set
++# CONFIG_ARCH_AT91 is not set
++# CONFIG_ARCH_BCMRING is not set
++# CONFIG_ARCH_CLPS711X is not set
++# CONFIG_ARCH_CNS3XXX is not set
++# CONFIG_ARCH_GEMINI is not set
++# CONFIG_ARCH_EBSA110 is not set
++# CONFIG_ARCH_EP93XX is not set
++# CONFIG_ARCH_FOOTBRIDGE is not set
++# CONFIG_ARCH_MXC is not set
++# CONFIG_ARCH_MXS is not set
++# CONFIG_ARCH_NETX is not set
++# CONFIG_ARCH_H720X is not set
++# CONFIG_ARCH_IOP13XX is not set
++# CONFIG_ARCH_IOP32X is not set
++# CONFIG_ARCH_IOP33X is not set
++# CONFIG_ARCH_IXP23XX is not set
++# CONFIG_ARCH_IXP2000 is not set
++# CONFIG_ARCH_IXP4XX is not set
++# CONFIG_ARCH_DOVE is not set
++# CONFIG_ARCH_KIRKWOOD is not set
++# CONFIG_ARCH_LOKI is not set
++# CONFIG_ARCH_LPC32XX is not set
++# CONFIG_ARCH_MV78XX0 is not set
++# CONFIG_ARCH_ORION5X is not set
++# CONFIG_ARCH_MMP is not set
++# CONFIG_ARCH_KS8695 is not set
++# CONFIG_ARCH_W90X900 is not set
++# CONFIG_ARCH_NUC93X is not set
++# CONFIG_ARCH_TEGRA is not set
++# CONFIG_ARCH_PNX4008 is not set
++# CONFIG_ARCH_PXA is not set
++# CONFIG_ARCH_MSM is not set
++# CONFIG_ARCH_SHMOBILE is not set
++# CONFIG_ARCH_RPC is not set
++# CONFIG_ARCH_SA1100 is not set
++CONFIG_ARCH_S3C2410=y
++# CONFIG_ARCH_S3C64XX is not set
++# CONFIG_ARCH_S5P64X0 is not set
++# CONFIG_ARCH_S5PC100 is not set
++# CONFIG_ARCH_S5PV210 is not set
++# CONFIG_ARCH_EXYNOS4 is not set
++# CONFIG_ARCH_SHARK is not set
++# CONFIG_ARCH_TCC_926 is not set
++# CONFIG_ARCH_U300 is not set
++# CONFIG_ARCH_U8500 is not set
++# CONFIG_ARCH_NOMADIK is not set
++# CONFIG_ARCH_DAVINCI is not set
++# CONFIG_ARCH_OMAP is not set
++# CONFIG_PLAT_SPEAR is not set
++# CONFIG_ARCH_VT8500 is not set
++# CONFIG_GPIO_PCA953X is not set
++CONFIG_KEYBOARD_GPIO_POLLED=y
++CONFIG_PLAT_SAMSUNG=y
++
++#
++# Boot options
++#
++# CONFIG_S3C_BOOT_ERROR_RESET is not set
++CONFIG_S3C_BOOT_UART_FORCE_FIFO=y
++CONFIG_S3C_LOWLEVEL_UART_PORT=0
++CONFIG_S3C_GPIO_CFG_S3C24XX=y
++CONFIG_S3C_GPIO_PULL_UP=y
++CONFIG_SAMSUNG_GPIO_EXTRA=0
++CONFIG_S3C_GPIO_SPACE=0
++CONFIG_S3C_ADC=y
++CONFIG_S3C_DEV_USB_HOST=y
++CONFIG_S3C_DEV_WDT=y
++CONFIG_S3C_DEV_NAND=y
++CONFIG_SAMSUNG_DEV_PWM=y
++CONFIG_S3C24XX_PWM=y
++CONFIG_S3C_DMA=y
++
++#
++# Power management
++#
++# CONFIG_SAMSUNG_PM_DEBUG is not set
++# CONFIG_SAMSUNG_PM_CHECK is not set
++
++#
++# Power Domain
++#
++CONFIG_PLAT_S3C24XX=y
++CONFIG_CPU_LLSERIAL_S3C2440_ONLY=y
++CONFIG_CPU_LLSERIAL_S3C2440=y
++CONFIG_S3C2410_CLOCK=y
++CONFIG_S3C24XX_GPIO_EXTRA=0
++CONFIG_S3C2410_DMA=y
++# CONFIG_S3C2410_DMA_DEBUG is not set
++CONFIG_MACH_SMDK=y
++
++#
++# System MMU
++#
++
++#
++# S3C2400 Machines
++#
++CONFIG_S3C2410_PM=y
++CONFIG_S3C2410_GPIO=y
++
++#
++# S3C2410 Machines
++#
++# CONFIG_ARCH_SMDK2410 is not set
++# CONFIG_ARCH_H1940 is not set
++# CONFIG_MACH_N30 is not set
++# CONFIG_ARCH_BAST is not set
++# CONFIG_MACH_OTOM is not set
++# CONFIG_MACH_AML_M5900 is not set
++# CONFIG_MACH_TCT_HAMMER is not set
++# CONFIG_MACH_VR1000 is not set
++# CONFIG_MACH_QT2410 is not set
++
++#
++# S3C2412 Machines
++#
++# CONFIG_MACH_JIVE is not set
++# CONFIG_MACH_SMDK2413 is not set
++# CONFIG_MACH_SMDK2412 is not set
++# CONFIG_MACH_VSTMS is not set
++
++#
++# S3C2416 Machines
++#
++# CONFIG_MACH_SMDK2416 is not set
++CONFIG_CPU_S3C2440=y
++CONFIG_CPU_S3C244X=y
++CONFIG_S3C2440_XTAL_16934400=y
++CONFIG_S3C2440_DMA=y
++
++#
++# S3C2440 and S3C2442 Machines
++#
++# CONFIG_MACH_ANUBIS is not set
++# CONFIG_MACH_NEO1973_GTA02 is not set
++# CONFIG_MACH_OSIRIS is not set
++# CONFIG_MACH_RX3715 is not set
++CONFIG_ARCH_S3C2440=y
++# CONFIG_MACH_NEXCODER_2440 is not set
++CONFIG_SMDK2440_CPU2440=y
++# CONFIG_SMDK2440_CPU2442 is not set
++# CONFIG_MACH_AT2440EVB is not set
++# CONFIG_MACH_MINI2440 is not set
++# CONFIG_MACH_RX1950 is not set
++
++#
++# S3C2443 Machines
++#
++# CONFIG_MACH_SMDK2443 is not set
++
++#
++# Processor Type
++#
++CONFIG_CPU_ARM920T=y
++CONFIG_CPU_32v4T=y
++CONFIG_CPU_ABRT_EV4T=y
++CONFIG_CPU_PABRT_LEGACY=y
++CONFIG_CPU_CACHE_V4WT=y
++CONFIG_CPU_CACHE_VIVT=y
++CONFIG_CPU_COPY_V4WB=y
++CONFIG_CPU_TLB_V4WBI=y
++CONFIG_CPU_CP15=y
++CONFIG_CPU_CP15_MMU=y
++CONFIG_CPU_USE_DOMAINS=y
++
++#
++# Processor Features
++#
++# CONFIG_ARM_THUMB is not set
++# CONFIG_CPU_ICACHE_DISABLE is not set
++# CONFIG_CPU_DCACHE_DISABLE is not set
++# CONFIG_CPU_DCACHE_WRITETHROUGH is not set
++CONFIG_ARM_L1_CACHE_SHIFT=5
++
++#
++# Bus support
++#
++# CONFIG_PCI_SYSCALL is not set
++# CONFIG_ARCH_SUPPORTS_MSI is not set
++# CONFIG_PCCARD is not set
++
++#
++# Kernel Features
++#
++CONFIG_VMSPLIT_3G=y
++# CONFIG_VMSPLIT_2G is not set
++# CONFIG_VMSPLIT_1G is not set
++CONFIG_PAGE_OFFSET=0xC0000000
++CONFIG_PREEMPT_NONE=y
++# CONFIG_PREEMPT_VOLUNTARY is not set
++# CONFIG_PREEMPT is not set
++CONFIG_HZ=200
++CONFIG_AEABI=y
++CONFIG_OABI_COMPAT=y
++# CONFIG_ARCH_SPARSEMEM_DEFAULT is not set
++# CONFIG_ARCH_SELECT_MEMORY_MODEL is not set
++CONFIG_HAVE_ARCH_PFN_VALID=y
++# CONFIG_HIGHMEM is not set
++CONFIG_SELECT_MEMORY_MODEL=y
++CONFIG_FLATMEM_MANUAL=y
++CONFIG_FLATMEM=y
++CONFIG_FLAT_NODE_MEM_MAP=y
++CONFIG_HAVE_MEMBLOCK=y
++CONFIG_PAGEFLAGS_EXTENDED=y
++CONFIG_SPLIT_PTLOCK_CPUS=999999
++# CONFIG_COMPACTION is not set
++# CONFIG_PHYS_ADDR_T_64BIT is not set
++CONFIG_ZONE_DMA_FLAG=0
++CONFIG_VIRT_TO_BUS=y
++# CONFIG_KSM is not set
++CONFIG_DEFAULT_MMAP_MIN_ADDR=4096
++CONFIG_NEED_PER_CPU_KM=y
++# CONFIG_CLEANCACHE is not set
++CONFIG_FORCE_MAX_ZONEORDER=11
++CONFIG_ALIGNMENT_TRAP=y
++# CONFIG_UACCESS_WITH_MEMCPY is not set
++# CONFIG_SECCOMP is not set
++# CONFIG_CC_STACKPROTECTOR is not set
++# CONFIG_DEPRECATED_PARAM_STRUCT is not set
++
++#
++# Boot options
++#
++# CONFIG_USE_OF is not set
++CONFIG_ZBOOT_ROM_TEXT=0x0
++CONFIG_ZBOOT_ROM_BSS=0x0
++CONFIG_CMDLINE="console=ttySAC0,115200 initrd=0x38000000,16M root=/dev/ram0 rw"
++CONFIG_CMDLINE_FROM_BOOTLOADER=y
++# CONFIG_CMDLINE_EXTEND is not set
++# CONFIG_CMDLINE_FORCE is not set
++# CONFIG_XIP_KERNEL is not set
++# CONFIG_KEXEC is not set
++# CONFIG_CRASH_DUMP is not set
++# CONFIG_AUTO_ZRELADDR is not set
++
++#
++# CPU Power Management
++#
++
++#
++# CPU Frequency scaling
++#
++# CONFIG_CPU_FREQ is not set
++# CONFIG_CPU_IDLE is not set
++
++#
++# Floating point emulation
++#
++
++#
++# At least one emulation must be selected
++#
++CONFIG_FPE_NWFPE=y
++CONFIG_FPE_NWFPE_XP=y
++# CONFIG_FPE_FASTFPE is not set
++
++#
++# Userspace binary formats
++#
++CONFIG_BINFMT_ELF=y
++# CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set
++CONFIG_HAVE_AOUT=y
++# CONFIG_BINFMT_AOUT is not set
++# CONFIG_BINFMT_MISC is not set
++
++#
++# Power management options
++#
++CONFIG_SUSPEND=y
++CONFIG_SUSPEND_FREEZER=y
++CONFIG_PM_SLEEP=y
++# CONFIG_PM_RUNTIME is not set
++CONFIG_PM=y
++# CONFIG_PM_DEBUG is not set
++# CONFIG_APM_EMULATION is not set
++CONFIG_ARCH_SUSPEND_POSSIBLE=y
++CONFIG_NET=y
++
++#
++# Networking options
++#
++CONFIG_PACKET=y
++CONFIG_UNIX=y
++# CONFIG_NET_KEY is not set
++CONFIG_INET=y
++CONFIG_IP_MULTICAST=y
++# CONFIG_IP_ADVANCED_ROUTER is not set
++CONFIG_IP_ROUTE_CLASSID=y
++CONFIG_IP_PNP=y
++CONFIG_IP_PNP_DHCP=y
++CONFIG_IP_PNP_BOOTP=y
++CONFIG_IP_PNP_RARP=y
++# CONFIG_NET_IPIP is not set
++# CONFIG_NET_IPGRE_DEMUX is not set
++CONFIG_IP_MROUTE=y
++# CONFIG_IP_PIMSM_V1 is not set
++# CONFIG_IP_PIMSM_V2 is not set
++# CONFIG_ARPD is not set
++# CONFIG_SYN_COOKIES is not set
++# CONFIG_INET_AH is not set
++# CONFIG_INET_ESP is not set
++# CONFIG_INET_IPCOMP is not set
++# CONFIG_INET_XFRM_TUNNEL is not set
++# CONFIG_INET_TUNNEL is not set
++# CONFIG_INET_XFRM_MODE_TRANSPORT is not set
++# CONFIG_INET_XFRM_MODE_TUNNEL is not set
++# CONFIG_INET_XFRM_MODE_BEET is not set
++# CONFIG_INET_LRO is not set
++CONFIG_INET_DIAG=y
++CONFIG_INET_TCP_DIAG=y
++# CONFIG_TCP_CONG_ADVANCED is not set
++CONFIG_TCP_CONG_CUBIC=y
++CONFIG_DEFAULT_TCP_CONG="cubic"
++# CONFIG_TCP_MD5SIG is not set
++# CONFIG_IPV6 is not set
++# CONFIG_NETWORK_SECMARK is not set
++# CONFIG_NETWORK_PHY_TIMESTAMPING is not set
++CONFIG_NETFILTER=y
++# CONFIG_NETFILTER_DEBUG is not set
++CONFIG_NETFILTER_ADVANCED=y
++
++#
++# Core Netfilter Configuration
++#
++CONFIG_NETFILTER_NETLINK=y
++CONFIG_NETFILTER_NETLINK_QUEUE=y
++CONFIG_NETFILTER_NETLINK_LOG=y
++CONFIG_NF_CONNTRACK=y
++CONFIG_NF_CONNTRACK_MARK=y
++CONFIG_NF_CONNTRACK_EVENTS=y
++CONFIG_NF_CONNTRACK_TIMESTAMP=y
++CONFIG_NF_CT_PROTO_DCCP=y
++CONFIG_NF_CT_PROTO_GRE=y
++CONFIG_NF_CT_PROTO_SCTP=y
++CONFIG_NF_CT_PROTO_UDPLITE=y
++CONFIG_NF_CONNTRACK_AMANDA=y
++CONFIG_NF_CONNTRACK_FTP=y
++CONFIG_NF_CONNTRACK_H323=y
++CONFIG_NF_CONNTRACK_IRC=y
++CONFIG_NF_CONNTRACK_BROADCAST=y
++CONFIG_NF_CONNTRACK_NETBIOS_NS=y
++CONFIG_NF_CONNTRACK_SNMP=y
++CONFIG_NF_CONNTRACK_PPTP=y
++CONFIG_NF_CONNTRACK_SANE=y
++CONFIG_NF_CONNTRACK_SIP=y
++CONFIG_NF_CONNTRACK_TFTP=y
++CONFIG_NF_CT_NETLINK=y
++# CONFIG_NETFILTER_TPROXY is not set
++CONFIG_NETFILTER_XTABLES=y
++
++#
++# Xtables combined modules
++#
++CONFIG_NETFILTER_XT_MARK=y
++CONFIG_NETFILTER_XT_CONNMARK=y
++# CONFIG_NETFILTER_XT_SET is not set
++
++#
++# Xtables targets
++#
++# CONFIG_NETFILTER_XT_TARGET_CHECKSUM is not set
++CONFIG_NETFILTER_XT_TARGET_CLASSIFY=y
++CONFIG_NETFILTER_XT_TARGET_CONNMARK=y
++# CONFIG_NETFILTER_XT_TARGET_CT is not set
++# CONFIG_NETFILTER_XT_TARGET_DSCP is not set
++CONFIG_NETFILTER_XT_TARGET_HL=y
++CONFIG_NETFILTER_XT_TARGET_IDLETIMER=y
++# CONFIG_NETFILTER_XT_TARGET_LED is not set
++CONFIG_NETFILTER_XT_TARGET_MARK=y
++CONFIG_NETFILTER_XT_TARGET_NFLOG=y
++CONFIG_NETFILTER_XT_TARGET_NFQUEUE=y
++# CONFIG_NETFILTER_XT_TARGET_NOTRACK is not set
++CONFIG_NETFILTER_XT_TARGET_RATEEST=y
++CONFIG_NETFILTER_XT_TARGET_TEE=y
++# CONFIG_NETFILTER_XT_TARGET_TRACE is not set
++CONFIG_NETFILTER_XT_TARGET_TCPMSS=y
++# CONFIG_NETFILTER_XT_TARGET_TCPOPTSTRIP is not set
++
++#
++# Xtables matches
++#
++CONFIG_NETFILTER_XT_MATCH_ADDRTYPE=y
++CONFIG_NETFILTER_XT_MATCH_CLUSTER=y
++CONFIG_NETFILTER_XT_MATCH_COMMENT=y
++CONFIG_NETFILTER_XT_MATCH_CONNBYTES=y
++CONFIG_NETFILTER_XT_MATCH_CONNLIMIT=y
++CONFIG_NETFILTER_XT_MATCH_CONNMARK=y
++CONFIG_NETFILTER_XT_MATCH_CONNTRACK=y
++CONFIG_NETFILTER_XT_MATCH_CPU=y
++CONFIG_NETFILTER_XT_MATCH_DCCP=y
++CONFIG_NETFILTER_XT_MATCH_DEVGROUP=y
++CONFIG_NETFILTER_XT_MATCH_DSCP=y
++CONFIG_NETFILTER_XT_MATCH_ESP=y
++CONFIG_NETFILTER_XT_MATCH_HASHLIMIT=y
++CONFIG_NETFILTER_XT_MATCH_HELPER=y
++CONFIG_NETFILTER_XT_MATCH_HL=y
++CONFIG_NETFILTER_XT_MATCH_IPRANGE=y
++CONFIG_NETFILTER_XT_MATCH_IPVS=y
++CONFIG_NETFILTER_XT_MATCH_LENGTH=y
++CONFIG_NETFILTER_XT_MATCH_LIMIT=y
++CONFIG_NETFILTER_XT_MATCH_MAC=y
++CONFIG_NETFILTER_XT_MATCH_MARK=y
++CONFIG_NETFILTER_XT_MATCH_MULTIPORT=y
++CONFIG_NETFILTER_XT_MATCH_OSF=y
++CONFIG_NETFILTER_XT_MATCH_OWNER=y
++CONFIG_NETFILTER_XT_MATCH_PKTTYPE=y
++CONFIG_NETFILTER_XT_MATCH_QUOTA=y
++CONFIG_NETFILTER_XT_MATCH_RATEEST=y
++CONFIG_NETFILTER_XT_MATCH_REALM=y
++CONFIG_NETFILTER_XT_MATCH_RECENT=y
++CONFIG_NETFILTER_XT_MATCH_SCTP=y
++CONFIG_NETFILTER_XT_MATCH_STATE=y
++CONFIG_NETFILTER_XT_MATCH_STATISTIC=y
++CONFIG_NETFILTER_XT_MATCH_STRING=y
++CONFIG_NETFILTER_XT_MATCH_TCPMSS=y
++CONFIG_NETFILTER_XT_MATCH_TIME=y
++CONFIG_NETFILTER_XT_MATCH_U32=y
++CONFIG_IP_SET=y
++CONFIG_IP_SET_MAX=256
++CONFIG_IP_SET_BITMAP_IP=y
++CONFIG_IP_SET_BITMAP_IPMAC=y
++CONFIG_IP_SET_BITMAP_PORT=y
++# CONFIG_IP_SET_HASH_IP is not set
++# CONFIG_IP_SET_HASH_IPPORT is not set
++# CONFIG_IP_SET_HASH_IPPORTIP is not set
++# CONFIG_IP_SET_HASH_IPPORTNET is not set
++# CONFIG_IP_SET_HASH_NET is not set
++# CONFIG_IP_SET_HASH_NETPORT is not set
++CONFIG_IP_SET_LIST_SET=y
++CONFIG_IP_VS=y
++# CONFIG_IP_VS_DEBUG is not set
++CONFIG_IP_VS_TAB_BITS=12
++
++#
++# IPVS transport protocol load balancing support
++#
++CONFIG_IP_VS_PROTO_TCP=y
++CONFIG_IP_VS_PROTO_UDP=y
++CONFIG_IP_VS_PROTO_AH_ESP=y
++CONFIG_IP_VS_PROTO_ESP=y
++CONFIG_IP_VS_PROTO_AH=y
++# CONFIG_IP_VS_PROTO_SCTP is not set
++
++#
++# IPVS scheduler
++#
++CONFIG_IP_VS_RR=y
++CONFIG_IP_VS_WRR=y
++CONFIG_IP_VS_LC=y
++CONFIG_IP_VS_WLC=y
++CONFIG_IP_VS_LBLC=y
++CONFIG_IP_VS_LBLCR=y
++CONFIG_IP_VS_DH=y
++CONFIG_IP_VS_SH=y
++CONFIG_IP_VS_SED=y
++CONFIG_IP_VS_NQ=y
++
++#
++# IPVS application helper
++#
++# CONFIG_IP_VS_FTP is not set
++CONFIG_IP_VS_NFCT=y
++# CONFIG_IP_VS_PE_SIP is not set
++
++#
++# IP: Netfilter Configuration
++#
++CONFIG_NF_DEFRAG_IPV4=y
++CONFIG_NF_CONNTRACK_IPV4=y
++CONFIG_NF_CONNTRACK_PROC_COMPAT=y
++CONFIG_IP_NF_QUEUE=y
++CONFIG_IP_NF_IPTABLES=y
++CONFIG_IP_NF_MATCH_AH=y
++CONFIG_IP_NF_MATCH_ECN=y
++CONFIG_IP_NF_MATCH_TTL=y
++CONFIG_IP_NF_FILTER=y
++CONFIG_IP_NF_TARGET_REJECT=y
++CONFIG_IP_NF_TARGET_LOG=y
++CONFIG_IP_NF_TARGET_ULOG=y
++CONFIG_NF_NAT=y
++CONFIG_NF_NAT_NEEDED=y
++CONFIG_IP_NF_TARGET_MASQUERADE=y
++CONFIG_IP_NF_TARGET_NETMAP=y
++CONFIG_IP_NF_TARGET_REDIRECT=y
++CONFIG_NF_NAT_SNMP_BASIC=y
++CONFIG_NF_NAT_PROTO_DCCP=y
++CONFIG_NF_NAT_PROTO_GRE=y
++CONFIG_NF_NAT_PROTO_UDPLITE=y
++CONFIG_NF_NAT_PROTO_SCTP=y
++CONFIG_NF_NAT_FTP=y
++CONFIG_NF_NAT_IRC=y
++CONFIG_NF_NAT_TFTP=y
++CONFIG_NF_NAT_AMANDA=y
++CONFIG_NF_NAT_PPTP=y
++CONFIG_NF_NAT_H323=y
++CONFIG_NF_NAT_SIP=y
++CONFIG_IP_NF_MANGLE=y
++CONFIG_IP_NF_TARGET_CLUSTERIP=y
++CONFIG_IP_NF_TARGET_ECN=y
++CONFIG_IP_NF_TARGET_TTL=y
++CONFIG_IP_NF_RAW=y
++CONFIG_IP_NF_ARPTABLES=y
++CONFIG_IP_NF_ARPFILTER=y
++CONFIG_IP_NF_ARP_MANGLE=y
++# CONFIG_IP_DCCP is not set
++# CONFIG_IP_SCTP is not set
++# CONFIG_RDS is not set
++# CONFIG_TIPC is not set
++# CONFIG_ATM is not set
++# CONFIG_L2TP is not set
++# CONFIG_BRIDGE is not set
++# CONFIG_NET_DSA is not set
++# CONFIG_VLAN_8021Q is not set
++# CONFIG_DECNET is not set
++# CONFIG_LLC2 is not set
++# CONFIG_IPX is not set
++# CONFIG_ATALK is not set
++# CONFIG_X25 is not set
++# CONFIG_LAPB is not set
++# CONFIG_ECONET is not set
++# CONFIG_WAN_ROUTER is not set
++# CONFIG_PHONET is not set
++# CONFIG_IEEE802154 is not set
++# CONFIG_NET_SCHED is not set
++# CONFIG_DCB is not set
++CONFIG_DNS_RESOLVER=y
++# CONFIG_BATMAN_ADV is not set
++
++#
++# Network testing
++#
++# CONFIG_NET_PKTGEN is not set
++# CONFIG_HAMRADIO is not set
++# CONFIG_CAN is not set
++# CONFIG_IRDA is not set
++CONFIG_BT=y
++CONFIG_BT_L2CAP=y
++CONFIG_BT_SCO=y
++CONFIG_BT_RFCOMM=y
++CONFIG_BT_RFCOMM_TTY=y
++CONFIG_BT_BNEP=y
++CONFIG_BT_BNEP_MC_FILTER=y
++CONFIG_BT_BNEP_PROTO_FILTER=y
++CONFIG_BT_HIDP=y
++
++#
++# Bluetooth device drivers
++#
++CONFIG_BT_HCIBTUSB=y
++CONFIG_BT_HCIBTSDIO=y
++CONFIG_BT_HCIUART=y
++CONFIG_BT_HCIUART_H4=y
++CONFIG_BT_HCIUART_BCSP=y
++CONFIG_BT_HCIUART_ATH3K=y
++CONFIG_BT_HCIUART_LL=y
++CONFIG_BT_HCIBCM203X=y
++CONFIG_BT_HCIBPA10X=y
++CONFIG_BT_HCIBFUSB=y
++CONFIG_BT_HCIVHCI=y
++CONFIG_BT_MRVL=y
++CONFIG_BT_MRVL_SDIO=y
++CONFIG_BT_ATH3K=y
++# CONFIG_AF_RXRPC is not set
++CONFIG_WIRELESS=y
++CONFIG_WEXT_CORE=y
++CONFIG_WEXT_PROC=y
++CONFIG_CFG80211=y
++# CONFIG_NL80211_TESTMODE is not set
++# CONFIG_CFG80211_DEVELOPER_WARNINGS is not set
++# CONFIG_CFG80211_REG_DEBUG is not set
++CONFIG_CFG80211_DEFAULT_PS=y
++CONFIG_CFG80211_INTERNAL_REGDB=y
++CONFIG_CFG80211_WEXT=y
++CONFIG_WIRELESS_EXT_SYSFS=y
++CONFIG_LIB80211=y
++# CONFIG_LIB80211_DEBUG is not set
++CONFIG_MAC80211=y
++CONFIG_MAC80211_HAS_RC=y
++# CONFIG_MAC80211_RC_PID is not set
++CONFIG_MAC80211_RC_MINSTREL=y
++CONFIG_MAC80211_RC_MINSTREL_HT=y
++CONFIG_MAC80211_RC_DEFAULT_MINSTREL=y
++CONFIG_MAC80211_RC_DEFAULT="minstrel_ht"
++# CONFIG_MAC80211_MESH is not set
++# CONFIG_MAC80211_LEDS is not set
++# CONFIG_MAC80211_DEBUG_MENU is not set
++# CONFIG_WIMAX is not set
++CONFIG_RFKILL=y
++CONFIG_RFKILL_LEDS=y
++CONFIG_RFKILL_INPUT=y
++# CONFIG_RFKILL_GPIO is not set
++# CONFIG_NET_9P is not set
++# CONFIG_CAIF is not set
++# CONFIG_CEPH_LIB is not set
++
++#
++# Device Drivers
++#
++
++#
++# Generic Driver Options
++#
++CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
++# CONFIG_DEVTMPFS is not set
++# CONFIG_STANDALONE is not set
++# CONFIG_PREVENT_FIRMWARE_BUILD is not set
++CONFIG_FW_LOADER=y
++CONFIG_FIRMWARE_IN_KERNEL=y
++CONFIG_EXTRA_FIRMWARE=""
++# CONFIG_SYS_HYPERVISOR is not set
++# CONFIG_CONNECTOR is not set
++CONFIG_MTD=y
++# CONFIG_MTD_DEBUG is not set
++# CONFIG_MTD_TESTS is not set
++# CONFIG_MTD_REDBOOT_PARTS is not set
++CONFIG_MTD_CMDLINE_PARTS=y
++# CONFIG_MTD_AFS_PARTS is not set
++# CONFIG_MTD_AR7_PARTS is not set
++
++#
++# User Modules And Translation Layers
++#
++CONFIG_MTD_CHAR=y
++CONFIG_MTD_BLKDEVS=y
++CONFIG_MTD_BLOCK=y
++# CONFIG_FTL is not set
++# CONFIG_NFTL is not set
++# CONFIG_INFTL is not set
++# CONFIG_RFD_FTL is not set
++# CONFIG_SSFDC is not set
++# CONFIG_SM_FTL is not set
++# CONFIG_MTD_OOPS is not set
++
++#
++# RAM/ROM/Flash chip drivers
++#
++CONFIG_MTD_CFI=y
++# CONFIG_MTD_JEDECPROBE is not set
++CONFIG_MTD_GEN_PROBE=y
++# CONFIG_MTD_CFI_ADV_OPTIONS is not set
++CONFIG_MTD_MAP_BANK_WIDTH_1=y
++CONFIG_MTD_MAP_BANK_WIDTH_2=y
++CONFIG_MTD_MAP_BANK_WIDTH_4=y
++# CONFIG_MTD_MAP_BANK_WIDTH_8 is not set
++# CONFIG_MTD_MAP_BANK_WIDTH_16 is not set
++# CONFIG_MTD_MAP_BANK_WIDTH_32 is not set
++CONFIG_MTD_CFI_I1=y
++CONFIG_MTD_CFI_I2=y
++# CONFIG_MTD_CFI_I4 is not set
++# CONFIG_MTD_CFI_I8 is not set
++CONFIG_MTD_CFI_INTELEXT=y
++# CONFIG_MTD_CFI_AMDSTD is not set
++# CONFIG_MTD_CFI_STAA is not set
++CONFIG_MTD_CFI_UTIL=y
++# CONFIG_MTD_RAM is not set
++# CONFIG_MTD_ROM is not set
++# CONFIG_MTD_ABSENT is not set
++
++#
++# Mapping drivers for chip access
++#
++# CONFIG_MTD_COMPLEX_MAPPINGS is not set
++CONFIG_MTD_PHYSMAP=y
++# CONFIG_MTD_PHYSMAP_COMPAT is not set
++# CONFIG_MTD_ARM_INTEGRATOR is not set
++# CONFIG_MTD_PLATRAM is not set
++
++#
++# Self-contained MTD device drivers
++#
++# CONFIG_MTD_DATAFLASH is not set
++# CONFIG_MTD_M25P80 is not set
++# CONFIG_MTD_SST25L is not set
++# CONFIG_MTD_SLRAM is not set
++# CONFIG_MTD_PHRAM is not set
++# CONFIG_MTD_MTDRAM is not set
++CONFIG_MTD_BLOCK2MTD=y
++
++#
++# Disk-On-Chip Device Drivers
++#
++# CONFIG_MTD_DOC2000 is not set
++# CONFIG_MTD_DOC2001 is not set
++# CONFIG_MTD_DOC2001PLUS is not set
++CONFIG_MTD_NAND_ECC=y
++# CONFIG_MTD_NAND_ECC_SMC is not set
++CONFIG_MTD_NAND=y
++# CONFIG_MTD_NAND_VERIFY_WRITE is not set
++# CONFIG_MTD_NAND_ECC_BCH is not set
++# CONFIG_MTD_SM_COMMON is not set
++# CONFIG_MTD_NAND_MUSEUM_IDS is not set
++# CONFIG_MTD_NAND_GPIO is not set
++CONFIG_MTD_NAND_IDS=y
++CONFIG_MTD_NAND_S3C2410=y
++# CONFIG_MTD_NAND_S3C2410_DEBUG is not set
++# CONFIG_MTD_NAND_S3C2410_HWECC is not set
++# CONFIG_MTD_NAND_S3C2410_CLKSTOP is not set
++# CONFIG_MTD_NAND_DISKONCHIP is not set
++# CONFIG_MTD_NAND_NANDSIM is not set
++# CONFIG_MTD_NAND_PLATFORM is not set
++# CONFIG_MTD_ALAUDA is not set
++# CONFIG_MTD_ONENAND is not set
++
++#
++# LPDDR flash memory drivers
++#
++# CONFIG_MTD_LPDDR is not set
++CONFIG_MTD_UBI=y
++CONFIG_MTD_UBI_WL_THRESHOLD=4096
++CONFIG_MTD_UBI_BEB_RESERVE=1
++CONFIG_MTD_UBI_GLUEBI=y
++# CONFIG_MTD_UBI_DEBUG is not set
++# CONFIG_PARPORT is not set
++CONFIG_BLK_DEV=y
++# CONFIG_BLK_DEV_COW_COMMON is not set
++CONFIG_BLK_DEV_LOOP=y
++# CONFIG_BLK_DEV_CRYPTOLOOP is not set
++
++#
++# DRBD disabled because PROC_FS, INET or CONNECTOR not selected
++#
++# CONFIG_BLK_DEV_NBD is not set
++# CONFIG_BLK_DEV_UB is not set
++CONFIG_BLK_DEV_RAM=y
++CONFIG_BLK_DEV_RAM_COUNT=1
++CONFIG_BLK_DEV_RAM_SIZE=16384
++# CONFIG_BLK_DEV_XIP is not set
++# CONFIG_CDROM_PKTCDVD is not set
++# CONFIG_ATA_OVER_ETH is not set
++# CONFIG_MG_DISK is not set
++# CONFIG_BLK_DEV_RBD is not set
++# CONFIG_SENSORS_LIS3LV02D is not set
++CONFIG_MISC_DEVICES=y
++# CONFIG_AD525X_DPOT is not set
++# CONFIG_INTEL_MID_PTI is not set
++# CONFIG_ICS932S401 is not set
++# CONFIG_ENCLOSURE_SERVICES is not set
++# CONFIG_APDS9802ALS is not set
++# CONFIG_ISL29003 is not set
++# CONFIG_ISL29020 is not set
++# CONFIG_SENSORS_TSL2550 is not set
++# CONFIG_SENSORS_BH1780 is not set
++# CONFIG_SENSORS_BH1770 is not set
++# CONFIG_SENSORS_APDS990X is not set
++# CONFIG_HMC6352 is not set
++# CONFIG_DS1682 is not set
++# CONFIG_TI_DAC7512 is not set
++# CONFIG_BMP085 is not set
++# CONFIG_C2PORT is not set
++
++#
++# EEPROM support
++#
++CONFIG_EEPROM_AT24=y
++# CONFIG_EEPROM_AT25 is not set
++# CONFIG_EEPROM_LEGACY is not set
++# CONFIG_EEPROM_MAX6875 is not set
++# CONFIG_EEPROM_93CX6 is not set
++# CONFIG_IWMC3200TOP is not set
++
++#
++# Texas Instruments shared transport line discipline
++#
++# CONFIG_TI_ST is not set
++# CONFIG_SENSORS_LIS3_SPI is not set
++# CONFIG_SENSORS_LIS3_I2C is not set
++CONFIG_HAVE_IDE=y
++# CONFIG_IDE is not set
++
++#
++# SCSI device support
++#
++CONFIG_SCSI_MOD=y
++# CONFIG_RAID_ATTRS is not set
++CONFIG_SCSI=y
++CONFIG_SCSI_DMA=y
++# CONFIG_SCSI_TGT is not set
++# CONFIG_SCSI_NETLINK is not set
++CONFIG_SCSI_PROC_FS=y
++
++#
++# SCSI support type (disk, tape, CD-ROM)
++#
++CONFIG_BLK_DEV_SD=y
++# CONFIG_CHR_DEV_ST is not set
++# CONFIG_CHR_DEV_OSST is not set
++# CONFIG_BLK_DEV_SR is not set
++CONFIG_CHR_DEV_SG=y
++# CONFIG_CHR_DEV_SCH is not set
++CONFIG_SCSI_MULTI_LUN=y
++# CONFIG_SCSI_CONSTANTS is not set
++# CONFIG_SCSI_LOGGING is not set
++CONFIG_SCSI_SCAN_ASYNC=y
++CONFIG_SCSI_WAIT_SCAN=m
++
++#
++# SCSI Transports
++#
++# CONFIG_SCSI_SPI_ATTRS is not set
++# CONFIG_SCSI_FC_ATTRS is not set
++# CONFIG_SCSI_ISCSI_ATTRS is not set
++# CONFIG_SCSI_SAS_ATTRS is not set
++# CONFIG_SCSI_SAS_LIBSAS is not set
++# CONFIG_SCSI_SRP_ATTRS is not set
++# CONFIG_SCSI_LOWLEVEL is not set
++# CONFIG_SCSI_DH is not set
++# CONFIG_SCSI_OSD_INITIATOR is not set
++# CONFIG_ATA is not set
++# CONFIG_MD is not set
++# CONFIG_TARGET_CORE is not set
++CONFIG_NETDEVICES=y
++# CONFIG_DUMMY is not set
++# CONFIG_BONDING is not set
++# CONFIG_MACVLAN is not set
++# CONFIG_EQUALIZER is not set
++# CONFIG_TUN is not set
++# CONFIG_VETH is not set
++CONFIG_MII=y
++# CONFIG_PHYLIB is not set
++CONFIG_NET_ETHERNET=y
++# CONFIG_AX88796 is not set
++# CONFIG_SMC91X is not set
++CONFIG_DM9000=y
++CONFIG_DM9000_DEBUGLEVEL=4
++# CONFIG_DM9000_FORCE_SIMPLE_PHY_POLL is not set
++# CONFIG_ENC28J60 is not set
++# CONFIG_ETHOC is not set
++# CONFIG_SMC911X is not set
++# CONFIG_SMSC911X is not set
++# CONFIG_DNET is not set
++# CONFIG_IBM_NEW_EMAC_ZMII is not set
++# CONFIG_IBM_NEW_EMAC_RGMII is not set
++# CONFIG_IBM_NEW_EMAC_TAH is not set
++# CONFIG_IBM_NEW_EMAC_EMAC4 is not set
++# CONFIG_IBM_NEW_EMAC_NO_FLOW_CTRL is not set
++# CONFIG_IBM_NEW_EMAC_MAL_CLR_ICINTSTAT is not set
++# CONFIG_IBM_NEW_EMAC_MAL_COMMON_ERR is not set
++# CONFIG_B44 is not set
++# CONFIG_KS8851 is not set
++# CONFIG_KS8851_MLL is not set
++# CONFIG_FTMAC100 is not set
++# CONFIG_NETDEV_1000 is not set
++# CONFIG_NETDEV_10000 is not set
++CONFIG_WLAN=y
++# CONFIG_LIBERTAS_THINFIRM is not set
++# CONFIG_AT76C50X_USB is not set
++# CONFIG_USB_ZD1201 is not set
++# CONFIG_USB_NET_RNDIS_WLAN is not set
++# CONFIG_RTL8187 is not set
++# CONFIG_MAC80211_HWSIM is not set
++# CONFIG_ATH_COMMON is not set
++# CONFIG_B43 is not set
++# CONFIG_B43LEGACY is not set
++# CONFIG_HOSTAP is not set
++# CONFIG_IWM is not set
++# CONFIG_LIBERTAS is not set
++# CONFIG_P54_COMMON is not set
++CONFIG_RT2X00=y
++# CONFIG_RT2500USB is not set
++# CONFIG_RT73USB is not set
++CONFIG_RT2800USB=y
++# CONFIG_RT2800USB_RT33XX is not set
++# CONFIG_RT2800USB_RT35XX is not set
++# CONFIG_RT2800USB_RT53XX is not set
++# CONFIG_RT2800USB_UNKNOWN is not set
++CONFIG_RT2800_LIB=y
++CONFIG_RT2X00_LIB_USB=y
++CONFIG_RT2X00_LIB=y
++CONFIG_RT2X00_LIB_FIRMWARE=y
++CONFIG_RT2X00_LIB_CRYPTO=y
++CONFIG_RT2X00_LIB_LEDS=y
++# CONFIG_RT2X00_DEBUG is not set
++# CONFIG_RTL8192SE is not set
++# CONFIG_RTL8192CU is not set
++# CONFIG_WL1251 is not set
++# CONFIG_WL12XX_MENU is not set
++# CONFIG_ZD1211RW is not set
++# CONFIG_MWIFIEX is not set
++
++#
++# Enable WiMAX (Networking options) to see the WiMAX drivers
++#
++
++#
++# USB Network Adapters
++#
++# CONFIG_USB_CATC is not set
++# CONFIG_USB_KAWETH is not set
++# CONFIG_USB_PEGASUS is not set
++# CONFIG_USB_RTL8150 is not set
++# CONFIG_USB_USBNET is not set
++# CONFIG_USB_HSO is not set
++# CONFIG_USB_IPHETH is not set
++# CONFIG_WAN is not set
++
++#
++# CAIF transport drivers
++#
++CONFIG_PPP=y
++CONFIG_PPP_MULTILINK=y
++CONFIG_PPP_FILTER=y
++CONFIG_PPP_ASYNC=y
++CONFIG_PPP_SYNC_TTY=y
++CONFIG_PPP_DEFLATE=y
++CONFIG_PPP_BSDCOMP=y
++CONFIG_PPP_MPPE=y
++CONFIG_PPPOE=y
++# CONFIG_SLIP is not set
++CONFIG_SLHC=y
++# CONFIG_NETCONSOLE is not set
++# CONFIG_NETPOLL is not set
++# CONFIG_NET_POLL_CONTROLLER is not set
++# CONFIG_ISDN is not set
++# CONFIG_PHONE is not set
++
++#
++# Input device support
++#
++CONFIG_INPUT=y
++# CONFIG_INPUT_FF_MEMLESS is not set
++CONFIG_INPUT_POLLDEV=y
++# CONFIG_INPUT_SPARSEKMAP is not set
++
++#
++# Userland interfaces
++#
++CONFIG_INPUT_MOUSEDEV=y
++# CONFIG_INPUT_MOUSEDEV_PSAUX is not set
++CONFIG_INPUT_MOUSEDEV_SCREEN_X=240
++CONFIG_INPUT_MOUSEDEV_SCREEN_Y=320
++# CONFIG_INPUT_JOYDEV is not set
++CONFIG_INPUT_EVDEV=y
++# CONFIG_INPUT_EVBUG is not set
++
++#
++# Input Device Drivers
++#
++CONFIG_INPUT_KEYBOARD=y
++# CONFIG_KEYBOARD_ADP5588 is not set
++# CONFIG_KEYBOARD_ADP5589 is not set
++# CONFIG_KEYBOARD_ATKBD is not set
++# CONFIG_KEYBOARD_QT1070 is not set
++# CONFIG_KEYBOARD_QT2160 is not set
++# CONFIG_KEYBOARD_LKKBD is not set
++CONFIG_KEYBOARD_GPIO=m
++# CONFIG_KEYBOARD_TCA6416 is not set
++# CONFIG_KEYBOARD_MATRIX is not set
++# CONFIG_KEYBOARD_LM8323 is not set
++# CONFIG_KEYBOARD_MAX7359 is not set
++# CONFIG_KEYBOARD_MCS is not set
++# CONFIG_KEYBOARD_MPR121 is not set
++# CONFIG_KEYBOARD_NEWTON is not set
++# CONFIG_KEYBOARD_OPENCORES is not set
++# CONFIG_KEYBOARD_STOWAWAY is not set
++# CONFIG_KEYBOARD_SUNKBD is not set
++# CONFIG_KEYBOARD_XTKBD is not set
++# CONFIG_INPUT_MOUSE is not set
++# CONFIG_INPUT_JOYSTICK is not set
++# CONFIG_INPUT_TABLET is not set
++CONFIG_INPUT_TOUCHSCREEN=y
++# CONFIG_TOUCHSCREEN_ADS7846 is not set
++# CONFIG_TOUCHSCREEN_AD7877 is not set
++# CONFIG_TOUCHSCREEN_AD7879 is not set
++# CONFIG_TOUCHSCREEN_ATMEL_MXT is not set
++# CONFIG_TOUCHSCREEN_BU21013 is not set
++# CONFIG_TOUCHSCREEN_CY8CTMG110 is not set
++# CONFIG_TOUCHSCREEN_DYNAPRO is not set
++# CONFIG_TOUCHSCREEN_HAMPSHIRE is not set
++# CONFIG_TOUCHSCREEN_EETI is not set
++# CONFIG_TOUCHSCREEN_FUJITSU is not set
++CONFIG_TOUCHSCREEN_S3C2410=y
++# CONFIG_TOUCHSCREEN_GUNZE is not set
++# CONFIG_TOUCHSCREEN_ELO is not set
++# CONFIG_TOUCHSCREEN_WACOM_W8001 is not set
++# CONFIG_TOUCHSCREEN_MAX11801 is not set
++# CONFIG_TOUCHSCREEN_MCS5000 is not set
++# CONFIG_TOUCHSCREEN_MTOUCH is not set
++# CONFIG_TOUCHSCREEN_INEXIO is not set
++# CONFIG_TOUCHSCREEN_MK712 is not set
++# CONFIG_TOUCHSCREEN_PENMOUNT is not set
++# CONFIG_TOUCHSCREEN_TOUCHRIGHT is not set
++# CONFIG_TOUCHSCREEN_TOUCHWIN is not set
++# CONFIG_TOUCHSCREEN_USB_COMPOSITE is not set
++# CONFIG_TOUCHSCREEN_TOUCHIT213 is not set
++# CONFIG_TOUCHSCREEN_TSC2005 is not set
++# CONFIG_TOUCHSCREEN_TSC2007 is not set
++# CONFIG_TOUCHSCREEN_W90X900 is not set
++# CONFIG_TOUCHSCREEN_ST1232 is not set
++# CONFIG_TOUCHSCREEN_TPS6507X is not set
++# CONFIG_INPUT_MISC is not set
++
++#
++# Hardware I/O ports
++#
++# CONFIG_SERIO is not set
++# CONFIG_GAMEPORT is not set
++
++#
++# Character devices
++#
++CONFIG_VT=y
++CONFIG_CONSOLE_TRANSLATIONS=y
++CONFIG_VT_CONSOLE=y
++CONFIG_HW_CONSOLE=y
++# CONFIG_VT_HW_CONSOLE_BINDING is not set
++CONFIG_UNIX98_PTYS=y
++# CONFIG_DEVPTS_MULTIPLE_INSTANCES is not set
++CONFIG_LEGACY_PTYS=y
++CONFIG_LEGACY_PTY_COUNT=5
++# CONFIG_SERIAL_NONSTANDARD is not set
++# CONFIG_N_GSM is not set
++# CONFIG_TRACE_SINK is not set
++CONFIG_DEVKMEM=y
++
++#
++# Serial drivers
++#
++# CONFIG_SERIAL_8250 is not set
++
++#
++# Non-8250 serial port support
++#
++CONFIG_SERIAL_SAMSUNG=y
++CONFIG_SERIAL_SAMSUNG_UARTS=3
++CONFIG_SERIAL_SAMSUNG_CONSOLE=y
++CONFIG_SERIAL_S3C2440=y
++# CONFIG_SERIAL_MAX3100 is not set
++# CONFIG_SERIAL_MAX3107 is not set
++CONFIG_SERIAL_CORE=y
++CONFIG_SERIAL_CORE_CONSOLE=y
++# CONFIG_SERIAL_TIMBERDALE is not set
++# CONFIG_SERIAL_ALTERA_JTAGUART is not set
++# CONFIG_SERIAL_ALTERA_UART is not set
++# CONFIG_SERIAL_IFX6X60 is not set
++# CONFIG_SERIAL_XILINX_PS_UART is not set
++# CONFIG_TTY_PRINTK is not set
++# CONFIG_HVC_DCC is not set
++# CONFIG_IPMI_HANDLER is not set
++# CONFIG_HW_RANDOM is not set
++# CONFIG_R3964 is not set
++# CONFIG_RAW_DRIVER is not set
++# CONFIG_TCG_TPM is not set
++# CONFIG_RAMOOPS is not set
++CONFIG_I2C=y
++CONFIG_I2C_BOARDINFO=y
++CONFIG_I2C_COMPAT=y
++CONFIG_I2C_CHARDEV=y
++# CONFIG_I2C_MUX is not set
++# CONFIG_I2C_HELPER_AUTO is not set
++CONFIG_I2C_SMBUS=y
++
++#
++# I2C Algorithms
++#
++CONFIG_I2C_ALGOBIT=y
++# CONFIG_I2C_ALGOPCF is not set
++# CONFIG_I2C_ALGOPCA is not set
++
++#
++# I2C Hardware Bus support
++#
++
++#
++# I2C system bus drivers (mostly embedded / system-on-chip)
++#
++# CONFIG_I2C_DESIGNWARE is not set
++# CONFIG_I2C_GPIO is not set
++# CONFIG_I2C_OCORES is not set
++# CONFIG_I2C_PCA_PLATFORM is not set
++# CONFIG_I2C_PXA_PCI is not set
++CONFIG_HAVE_S3C2410_I2C=y
++CONFIG_I2C_S3C2410=y
++# CONFIG_I2C_SIMTEC is not set
++# CONFIG_I2C_XILINX is not set
++
++#
++# External I2C/SMBus adapter drivers
++#
++# CONFIG_I2C_DIOLAN_U2C is not set
++# CONFIG_I2C_PARPORT_LIGHT is not set
++# CONFIG_I2C_TAOS_EVM is not set
++# CONFIG_I2C_TINY_USB is not set
++
++#
++# Other I2C/SMBus bus drivers
++#
++# CONFIG_I2C_STUB is not set
++# CONFIG_I2C_DEBUG_CORE is not set
++# CONFIG_I2C_DEBUG_ALGO is not set
++# CONFIG_I2C_DEBUG_BUS is not set
++CONFIG_SPI=y
++CONFIG_SPI_MASTER=y
++
++#
++# SPI Master Controller Drivers
++#
++# CONFIG_SPI_ALTERA is not set
++CONFIG_SPI_BITBANG=y
++# CONFIG_SPI_GPIO is not set
++# CONFIG_SPI_OC_TINY is not set
++# CONFIG_SPI_PXA2XX_PCI is not set
++CONFIG_SPI_S3C24XX=y
++# CONFIG_SPI_S3C24XX_FIQ is not set
++# CONFIG_SPI_S3C24XX_GPIO is not set
++# CONFIG_SPI_XILINX is not set
++# CONFIG_SPI_DESIGNWARE is not set
++
++#
++# SPI Protocol Masters
++#
++# CONFIG_SPI_SPIDEV is not set
++# CONFIG_SPI_TLE62X0 is not set
++
++#
++# PPS support
++#
++# CONFIG_PPS is not set
++
++#
++# PPS generators support
++#
++
++#
++# PTP clock support
++#
++
++#
++# Enable Device Drivers -> PPS to see the PTP clock options.
++#
++CONFIG_ARCH_REQUIRE_GPIOLIB=y
++CONFIG_GPIOLIB=y
++# CONFIG_GPIO_SYSFS is not set
++
++#
++# Memory mapped GPIO drivers:
++#
++# CONFIG_GPIO_BASIC_MMIO is not set
++# CONFIG_GPIO_IT8761E is not set
++
++#
++# I2C GPIO expanders:
++#
++# CONFIG_GPIO_MAX7300 is not set
++# CONFIG_GPIO_MAX732X is not set
++# CONFIG_GPIO_PCF857X is not set
++# CONFIG_GPIO_SX150X is not set
++# CONFIG_GPIO_ADP5588 is not set
++
++#
++# PCI GPIO expanders:
++#
++
++#
++# SPI GPIO expanders:
++#
++# CONFIG_GPIO_MAX7301 is not set
++# CONFIG_GPIO_MCP23S08 is not set
++# CONFIG_GPIO_MC33880 is not set
++# CONFIG_GPIO_74X164 is not set
++
++#
++# AC97 GPIO expanders:
++#
++
++#
++# MODULbus GPIO expanders:
++#
++# CONFIG_W1 is not set
++# CONFIG_POWER_SUPPLY is not set
++# CONFIG_HWMON is not set
++# CONFIG_THERMAL is not set
++# CONFIG_WATCHDOG is not set
++CONFIG_SSB_POSSIBLE=y
++
++#
++# Sonics Silicon Backplane
++#
++# CONFIG_SSB is not set
++CONFIG_BCMA_POSSIBLE=y
++
++#
++# Broadcom specific AMBA
++#
++# CONFIG_BCMA is not set
++# CONFIG_MFD_SUPPORT is not set
++# CONFIG_REGULATOR is not set
++CONFIG_MEDIA_SUPPORT=y
++
++#
++# Multimedia core support
++#
++CONFIG_MEDIA_CONTROLLER=y
++CONFIG_VIDEO_DEV=y
++CONFIG_VIDEO_V4L2_COMMON=y
++CONFIG_VIDEO_V4L2_SUBDEV_API=y
++# CONFIG_DVB_CORE is not set
++CONFIG_VIDEO_MEDIA=y
++
++#
++# Multimedia drivers
++#
++# CONFIG_RC_CORE is not set
++# CONFIG_MEDIA_ATTACH is not set
++CONFIG_MEDIA_TUNER=y
++# CONFIG_MEDIA_TUNER_CUSTOMISE is not set
++CONFIG_MEDIA_TUNER_SIMPLE=y
++CONFIG_MEDIA_TUNER_TDA8290=y
++CONFIG_MEDIA_TUNER_TDA827X=y
++CONFIG_MEDIA_TUNER_TDA18271=y
++CONFIG_MEDIA_TUNER_TDA9887=y
++CONFIG_MEDIA_TUNER_TEA5761=y
++CONFIG_MEDIA_TUNER_TEA5767=y
++CONFIG_MEDIA_TUNER_MT20XX=y
++CONFIG_MEDIA_TUNER_XC2028=y
++CONFIG_MEDIA_TUNER_XC5000=y
++CONFIG_MEDIA_TUNER_MC44S803=y
++CONFIG_VIDEO_V4L2=y
++CONFIG_VIDEO_CAPTURE_DRIVERS=y
++# CONFIG_VIDEO_ADV_DEBUG is not set
++# CONFIG_VIDEO_FIXED_MINOR_RANGES is not set
++# CONFIG_VIDEO_HELPER_CHIPS_AUTO is not set
++
++#
++# Encoders, decoders, sensors and other helper chips
++#
++
++#
++# Audio decoders, processors and mixers
++#
++# CONFIG_VIDEO_TVAUDIO is not set
++# CONFIG_VIDEO_TDA7432 is not set
++# CONFIG_VIDEO_TDA9840 is not set
++# CONFIG_VIDEO_TEA6415C is not set
++# CONFIG_VIDEO_TEA6420 is not set
++# CONFIG_VIDEO_MSP3400 is not set
++# CONFIG_VIDEO_CS5345 is not set
++# CONFIG_VIDEO_CS53L32A is not set
++# CONFIG_VIDEO_TLV320AIC23B is not set
++# CONFIG_VIDEO_WM8775 is not set
++# CONFIG_VIDEO_WM8739 is not set
++# CONFIG_VIDEO_VP27SMPX is not set
++
++#
++# RDS decoders
++#
++# CONFIG_VIDEO_SAA6588 is not set
++
++#
++# Video decoders
++#
++# CONFIG_VIDEO_ADV7180 is not set
++# CONFIG_VIDEO_BT819 is not set
++# CONFIG_VIDEO_BT856 is not set
++# CONFIG_VIDEO_BT866 is not set
++# CONFIG_VIDEO_KS0127 is not set
++# CONFIG_VIDEO_SAA7110 is not set
++# CONFIG_VIDEO_SAA711X is not set
++# CONFIG_VIDEO_SAA7191 is not set
++# CONFIG_VIDEO_TVP514X is not set
++# CONFIG_VIDEO_TVP5150 is not set
++# CONFIG_VIDEO_TVP7002 is not set
++# CONFIG_VIDEO_VPX3220 is not set
++
++#
++# Video and audio decoders
++#
++# CONFIG_VIDEO_SAA717X is not set
++# CONFIG_VIDEO_CX25840 is not set
++
++#
++# MPEG video encoders
++#
++# CONFIG_VIDEO_CX2341X is not set
++
++#
++# Video encoders
++#
++# CONFIG_VIDEO_SAA7127 is not set
++# CONFIG_VIDEO_SAA7185 is not set
++# CONFIG_VIDEO_ADV7170 is not set
++# CONFIG_VIDEO_ADV7175 is not set
++# CONFIG_VIDEO_ADV7343 is not set
++# CONFIG_VIDEO_AK881X is not set
++
++#
++# Camera sensor devices
++#
++# CONFIG_VIDEO_OV7670 is not set
++# CONFIG_VIDEO_MT9V011 is not set
++# CONFIG_VIDEO_MT9V032 is not set
++# CONFIG_VIDEO_TCM825X is not set
++
++#
++# Video improvement chips
++#
++# CONFIG_VIDEO_UPD64031A is not set
++# CONFIG_VIDEO_UPD64083 is not set
++
++#
++# Miscelaneous helper chips
++#
++# CONFIG_VIDEO_THS7303 is not set
++# CONFIG_VIDEO_M52790 is not set
++# CONFIG_VIDEO_VIVI is not set
++# CONFIG_VIDEO_CPIA2 is not set
++# CONFIG_VIDEO_SR030PC30 is not set
++# CONFIG_VIDEO_NOON010PC30 is not set
++# CONFIG_VIDEO_M5MOLS is not set
++# CONFIG_SOC_CAMERA is not set
++CONFIG_V4L_USB_DRIVERS=y
++CONFIG_USB_VIDEO_CLASS=y
++CONFIG_USB_VIDEO_CLASS_INPUT_EVDEV=y
++CONFIG_USB_GSPCA=y
++# CONFIG_USB_M5602 is not set
++# CONFIG_USB_STV06XX is not set
++# CONFIG_USB_GL860 is not set
++# CONFIG_USB_GSPCA_BENQ is not set
++# CONFIG_USB_GSPCA_CONEX is not set
++# CONFIG_USB_GSPCA_CPIA1 is not set
++# CONFIG_USB_GSPCA_ETOMS is not set
++# CONFIG_USB_GSPCA_FINEPIX is not set
++# CONFIG_USB_GSPCA_JEILINJ is not set
++# CONFIG_USB_GSPCA_KINECT is not set
++# CONFIG_USB_GSPCA_KONICA is not set
++# CONFIG_USB_GSPCA_MARS is not set
++# CONFIG_USB_GSPCA_MR97310A is not set
++# CONFIG_USB_GSPCA_NW80X is not set
++# CONFIG_USB_GSPCA_OV519 is not set
++# CONFIG_USB_GSPCA_OV534 is not set
++# CONFIG_USB_GSPCA_OV534_9 is not set
++# CONFIG_USB_GSPCA_PAC207 is not set
++# CONFIG_USB_GSPCA_PAC7302 is not set
++# CONFIG_USB_GSPCA_PAC7311 is not set
++# CONFIG_USB_GSPCA_SN9C2028 is not set
++# CONFIG_USB_GSPCA_SN9C20X is not set
++# CONFIG_USB_GSPCA_SONIXB is not set
++# CONFIG_USB_GSPCA_SONIXJ is not set
++# CONFIG_USB_GSPCA_SPCA500 is not set
++# CONFIG_USB_GSPCA_SPCA501 is not set
++# CONFIG_USB_GSPCA_SPCA505 is not set
++# CONFIG_USB_GSPCA_SPCA506 is not set
++# CONFIG_USB_GSPCA_SPCA508 is not set
++# CONFIG_USB_GSPCA_SPCA561 is not set
++# CONFIG_USB_GSPCA_SPCA1528 is not set
++# CONFIG_USB_GSPCA_SQ905 is not set
++# CONFIG_USB_GSPCA_SQ905C is not set
++# CONFIG_USB_GSPCA_SQ930X is not set
++# CONFIG_USB_GSPCA_STK014 is not set
++# CONFIG_USB_GSPCA_STV0680 is not set
++# CONFIG_USB_GSPCA_SUNPLUS is not set
++# CONFIG_USB_GSPCA_T613 is not set
++# CONFIG_USB_GSPCA_TV8532 is not set
++# CONFIG_USB_GSPCA_VC032X is not set
++# CONFIG_USB_GSPCA_VICAM is not set
++# CONFIG_USB_GSPCA_XIRLINK_CIT is not set
++# CONFIG_USB_GSPCA_ZC3XX is not set
++# CONFIG_VIDEO_PVRUSB2 is not set
++# CONFIG_VIDEO_HDPVR is not set
++# CONFIG_VIDEO_USBVISION is not set
++# CONFIG_USB_ET61X251 is not set
++# CONFIG_USB_SN9C102 is not set
++# CONFIG_USB_PWC is not set
++# CONFIG_USB_ZR364XX is not set
++# CONFIG_USB_STKWEBCAM is not set
++# CONFIG_USB_S2255 is not set
++# CONFIG_V4L_MEM2MEM_DRIVERS is not set
++# CONFIG_RADIO_ADAPTERS is not set
++
++#
++# Graphics support
++#
++# CONFIG_DRM is not set
++# CONFIG_VGASTATE is not set
++# CONFIG_VIDEO_OUTPUT_CONTROL is not set
++CONFIG_FB=y
++CONFIG_FIRMWARE_EDID=y
++# CONFIG_FB_DDC is not set
++# CONFIG_FB_BOOT_VESA_SUPPORT is not set
++CONFIG_FB_CFB_FILLRECT=y
++CONFIG_FB_CFB_COPYAREA=y
++CONFIG_FB_CFB_IMAGEBLIT=y
++# CONFIG_FB_CFB_REV_PIXELS_IN_BYTE is not set
++# CONFIG_FB_SYS_FILLRECT is not set
++# CONFIG_FB_SYS_COPYAREA is not set
++# CONFIG_FB_SYS_IMAGEBLIT is not set
++# CONFIG_FB_FOREIGN_ENDIAN is not set
++# CONFIG_FB_SYS_FOPS is not set
++# CONFIG_FB_WMT_GE_ROPS is not set
++# CONFIG_FB_SVGALIB is not set
++# CONFIG_FB_MACMODES is not set
++# CONFIG_FB_BACKLIGHT is not set
++CONFIG_FB_MODE_HELPERS=y
++# CONFIG_FB_TILEBLITTING is not set
++
++#
++# Frame buffer hardware drivers
++#
++# CONFIG_FB_S1D13XXX is not set
++CONFIG_FB_S3C2410=y
++CONFIG_FB_S3C2410_DEBUG=y
++# CONFIG_FB_UDL is not set
++# CONFIG_FB_VIRTUAL is not set
++# CONFIG_FB_METRONOME is not set
++# CONFIG_FB_BROADSHEET is not set
++# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
++
++#
++# Display device support
++#
++# CONFIG_DISPLAY_SUPPORT is not set
++
++#
++# Console display driver support
++#
++CONFIG_DUMMY_CONSOLE=y
++CONFIG_FRAMEBUFFER_CONSOLE=y
++# CONFIG_FRAMEBUFFER_CONSOLE_DETECT_PRIMARY is not set
++# CONFIG_FRAMEBUFFER_CONSOLE_ROTATION is not set
++# CONFIG_FONTS is not set
++CONFIG_FONT_8x8=y
++CONFIG_FONT_8x16=y
++CONFIG_LOGO=y
++# CONFIG_LOGO_LINUX_MONO is not set
++# CONFIG_LOGO_LINUX_VGA16 is not set
++CONFIG_LOGO_LINUX_CLUT224=y
++CONFIG_SOUND=y
++CONFIG_SOUND_OSS_CORE=y
++# CONFIG_SOUND_OSS_CORE_PRECLAIM is not set
++CONFIG_SND=y
++CONFIG_SND_TIMER=y
++CONFIG_SND_PCM=y
++CONFIG_SND_JACK=y
++# CONFIG_SND_SEQUENCER is not set
++CONFIG_SND_OSSEMUL=y
++CONFIG_SND_MIXER_OSS=y
++CONFIG_SND_PCM_OSS=y
++CONFIG_SND_PCM_OSS_PLUGINS=y
++CONFIG_SND_DYNAMIC_MINORS=y
++CONFIG_SND_SUPPORT_OLD_API=y
++CONFIG_SND_VERBOSE_PROCFS=y
++CONFIG_SND_VERBOSE_PRINTK=y
++# CONFIG_SND_DEBUG is not set
++# CONFIG_SND_RAWMIDI_SEQ is not set
++# CONFIG_SND_OPL3_LIB_SEQ is not set
++# CONFIG_SND_OPL4_LIB_SEQ is not set
++# CONFIG_SND_SBAWE_SEQ is not set
++# CONFIG_SND_EMU10K1_SEQ is not set
++# CONFIG_SND_DRIVERS is not set
++# CONFIG_SND_ARM is not set
++# CONFIG_SND_SPI is not set
++# CONFIG_SND_USB is not set
++CONFIG_SND_SOC=y
++# CONFIG_SND_SOC_CACHE_LZO is not set
++CONFIG_SND_SOC_SAMSUNG=y
++CONFIG_SND_S3C24XX_I2S=y
++# CONFIG_SND_SOC_SAMSUNG_LN2440SBC_ALC650 is not set
++CONFIG_SND_SOC_SAMSUNG_S3C24XX_UDA134X=y
++# CONFIG_SND_SOC_SAMSUNG_SIMTEC_TLV320AIC23 is not set
++# CONFIG_SND_SOC_SAMSUNG_SIMTEC_HERMES is not set
++CONFIG_SND_SOC_I2C_AND_SPI=y
++# CONFIG_SND_SOC_ALL_CODECS is not set
++CONFIG_SND_SOC_L3=y
++CONFIG_SND_SOC_UDA134X=y
++# CONFIG_SOUND_PRIME is not set
++CONFIG_HID_SUPPORT=y
++CONFIG_HID=y
++# CONFIG_HIDRAW is not set
++
++#
++# USB Input Devices
++#
++CONFIG_USB_HID=y
++# CONFIG_HID_PID is not set
++# CONFIG_USB_HIDDEV is not set
++
++#
++# Special HID drivers
++#
++# CONFIG_HID_A4TECH is not set
++# CONFIG_HID_ACRUX is not set
++# CONFIG_HID_APPLE is not set
++# CONFIG_HID_BELKIN is not set
++# CONFIG_HID_CHERRY is not set
++# CONFIG_HID_CHICONY is not set
++# CONFIG_HID_PRODIKEYS is not set
++# CONFIG_HID_CYPRESS is not set
++# CONFIG_HID_DRAGONRISE is not set
++# CONFIG_HID_EMS_FF is not set
++# CONFIG_HID_ELECOM is not set
++# CONFIG_HID_EZKEY is not set
++# CONFIG_HID_KEYTOUCH is not set
++# CONFIG_HID_KYE is not set
++# CONFIG_HID_UCLOGIC is not set
++# CONFIG_HID_WALTOP is not set
++# CONFIG_HID_GYRATION is not set
++# CONFIG_HID_TWINHAN is not set
++# CONFIG_HID_KENSINGTON is not set
++# CONFIG_HID_LCPOWER is not set
++# CONFIG_HID_LOGITECH is not set
++# CONFIG_HID_MAGICMOUSE is not set
++# CONFIG_HID_MICROSOFT is not set
++# CONFIG_HID_MONTEREY is not set
++# CONFIG_HID_MULTITOUCH is not set
++# CONFIG_HID_NTRIG is not set
++# CONFIG_HID_ORTEK is not set
++# CONFIG_HID_PANTHERLORD is not set
++# CONFIG_HID_PETALYNX is not set
++# CONFIG_HID_PICOLCD is not set
++# CONFIG_HID_QUANTA is not set
++# CONFIG_HID_ROCCAT is not set
++# CONFIG_HID_ROCCAT_ARVO is not set
++# CONFIG_HID_ROCCAT_KONE is not set
++# CONFIG_HID_ROCCAT_KONEPLUS is not set
++# CONFIG_HID_ROCCAT_KOVAPLUS is not set
++# CONFIG_HID_ROCCAT_PYRA is not set
++# CONFIG_HID_SAMSUNG is not set
++# CONFIG_HID_SONY is not set
++# CONFIG_HID_SUNPLUS is not set
++# CONFIG_HID_GREENASIA is not set
++# CONFIG_HID_SMARTJOYPLUS is not set
++# CONFIG_HID_TOPSEED is not set
++# CONFIG_HID_THRUSTMASTER is not set
++# CONFIG_HID_WACOM is not set
++# CONFIG_HID_ZEROPLUS is not set
++# CONFIG_HID_ZYDACRON is not set
++CONFIG_USB_SUPPORT=y
++CONFIG_USB_ARCH_HAS_HCD=y
++CONFIG_USB_ARCH_HAS_OHCI=y
++# CONFIG_USB_ARCH_HAS_EHCI is not set
++CONFIG_USB=y
++# CONFIG_USB_DEBUG is not set
++CONFIG_USB_ANNOUNCE_NEW_DEVICES=y
++
++#
++# Miscellaneous USB options
++#
++CONFIG_USB_DEVICEFS=y
++CONFIG_USB_DEVICE_CLASS=y
++CONFIG_USB_DYNAMIC_MINORS=y
++# CONFIG_USB_OTG_WHITELIST is not set
++# CONFIG_USB_OTG_BLACKLIST_HUB is not set
++# CONFIG_USB_MON is not set
++# CONFIG_USB_WUSB is not set
++# CONFIG_USB_WUSB_CBAF is not set
++
++#
++# USB Host Controller Drivers
++#
++# CONFIG_USB_C67X00_HCD is not set
++# CONFIG_USB_OXU210HP_HCD is not set
++# CONFIG_USB_ISP116X_HCD is not set
++# CONFIG_USB_ISP1760_HCD is not set
++# CONFIG_USB_ISP1362_HCD is not set
++CONFIG_USB_OHCI_HCD=y
++# CONFIG_USB_OHCI_BIG_ENDIAN_DESC is not set
++# CONFIG_USB_OHCI_BIG_ENDIAN_MMIO is not set
++CONFIG_USB_OHCI_LITTLE_ENDIAN=y
++# CONFIG_USB_SL811_HCD is not set
++# CONFIG_USB_R8A66597_HCD is not set
++# CONFIG_USB_HWA_HCD is not set
++# CONFIG_USB_MUSB_HDRC is not set
++
++#
++# USB Device Class drivers
++#
++# CONFIG_USB_ACM is not set
++# CONFIG_USB_PRINTER is not set
++# CONFIG_USB_WDM is not set
++# CONFIG_USB_TMC is not set
++
++#
++# NOTE: USB_STORAGE depends on SCSI but BLK_DEV_SD may
++#
++
++#
++# also be needed; see USB_STORAGE Help for more info
++#
++CONFIG_USB_STORAGE=y
++# CONFIG_USB_STORAGE_DEBUG is not set
++# CONFIG_USB_STORAGE_REALTEK is not set
++# CONFIG_USB_STORAGE_DATAFAB is not set
++# CONFIG_USB_STORAGE_FREECOM is not set
++# CONFIG_USB_STORAGE_ISD200 is not set
++# CONFIG_USB_STORAGE_USBAT is not set
++# CONFIG_USB_STORAGE_SDDR09 is not set
++# CONFIG_USB_STORAGE_SDDR55 is not set
++# CONFIG_USB_STORAGE_JUMPSHOT is not set
++# CONFIG_USB_STORAGE_ALAUDA is not set
++# CONFIG_USB_STORAGE_ONETOUCH is not set
++# CONFIG_USB_STORAGE_KARMA is not set
++# CONFIG_USB_STORAGE_CYPRESS_ATACB is not set
++# CONFIG_USB_STORAGE_ENE_UB6250 is not set
++# CONFIG_USB_UAS is not set
++# CONFIG_USB_LIBUSUAL is not set
++
++#
++# USB Imaging devices
++#
++# CONFIG_USB_MDC800 is not set
++# CONFIG_USB_MICROTEK is not set
++
++#
++# USB port drivers
++#
++CONFIG_USB_SERIAL=y
++# CONFIG_USB_SERIAL_CONSOLE is not set
++# CONFIG_USB_EZUSB is not set
++# CONFIG_USB_SERIAL_GENERIC is not set
++# CONFIG_USB_SERIAL_AIRCABLE is not set
++# CONFIG_USB_SERIAL_ARK3116 is not set
++# CONFIG_USB_SERIAL_BELKIN is not set
++CONFIG_USB_SERIAL_CH341=y
++# CONFIG_USB_SERIAL_WHITEHEAT is not set
++# CONFIG_USB_SERIAL_DIGI_ACCELEPORT is not set
++# CONFIG_USB_SERIAL_CP210X is not set
++# CONFIG_USB_SERIAL_CYPRESS_M8 is not set
++# CONFIG_USB_SERIAL_EMPEG is not set
++CONFIG_USB_SERIAL_FTDI_SIO=y
++# CONFIG_USB_SERIAL_FUNSOFT is not set
++# CONFIG_USB_SERIAL_VISOR is not set
++# CONFIG_USB_SERIAL_IPAQ is not set
++# CONFIG_USB_SERIAL_IR is not set
++# CONFIG_USB_SERIAL_EDGEPORT is not set
++# CONFIG_USB_SERIAL_EDGEPORT_TI is not set
++# CONFIG_USB_SERIAL_GARMIN is not set
++# CONFIG_USB_SERIAL_IPW is not set
++# CONFIG_USB_SERIAL_IUU is not set
++# CONFIG_USB_SERIAL_KEYSPAN_PDA is not set
++# CONFIG_USB_SERIAL_KEYSPAN is not set
++# CONFIG_USB_SERIAL_KLSI is not set
++# CONFIG_USB_SERIAL_KOBIL_SCT is not set
++# CONFIG_USB_SERIAL_MCT_U232 is not set
++# CONFIG_USB_SERIAL_MOS7720 is not set
++# CONFIG_USB_SERIAL_MOS7840 is not set
++# CONFIG_USB_SERIAL_MOTOROLA is not set
++# CONFIG_USB_SERIAL_NAVMAN is not set
++CONFIG_USB_SERIAL_PL2303=y
++# CONFIG_USB_SERIAL_OTI6858 is not set
++# CONFIG_USB_SERIAL_QCAUX is not set
++# CONFIG_USB_SERIAL_QUALCOMM is not set
++# CONFIG_USB_SERIAL_SPCP8X5 is not set
++# CONFIG_USB_SERIAL_HP4X is not set
++# CONFIG_USB_SERIAL_SAFE is not set
++# CONFIG_USB_SERIAL_SIEMENS_MPI is not set
++# CONFIG_USB_SERIAL_SIERRAWIRELESS is not set
++# CONFIG_USB_SERIAL_SYMBOL is not set
++# CONFIG_USB_SERIAL_TI is not set
++# CONFIG_USB_SERIAL_CYBERJACK is not set
++# CONFIG_USB_SERIAL_XIRCOM is not set
++CONFIG_USB_SERIAL_WWAN=y
++CONFIG_USB_SERIAL_OPTION=y
++# CONFIG_USB_SERIAL_OMNINET is not set
++# CONFIG_USB_SERIAL_OPTICON is not set
++# CONFIG_USB_SERIAL_VIVOPAY_SERIAL is not set
++# CONFIG_USB_SERIAL_ZIO is not set
++# CONFIG_USB_SERIAL_SSU100 is not set
++# CONFIG_USB_SERIAL_DEBUG is not set
++
++#
++# USB Miscellaneous drivers
++#
++# CONFIG_USB_EMI62 is not set
++# CONFIG_USB_EMI26 is not set
++# CONFIG_USB_ADUTUX is not set
++# CONFIG_USB_SEVSEG is not set
++# CONFIG_USB_RIO500 is not set
++# CONFIG_USB_LEGOTOWER is not set
++# CONFIG_USB_LCD is not set
++# CONFIG_USB_LED is not set
++# CONFIG_USB_CYPRESS_CY7C63 is not set
++# CONFIG_USB_CYTHERM is not set
++# CONFIG_USB_IDMOUSE is not set
++# CONFIG_USB_FTDI_ELAN is not set
++# CONFIG_USB_APPLEDISPLAY is not set
++# CONFIG_USB_LD is not set
++# CONFIG_USB_TRANCEVIBRATOR is not set
++# CONFIG_USB_IOWARRIOR is not set
++# CONFIG_USB_TEST is not set
++# CONFIG_USB_ISIGHTFW is not set
++# CONFIG_USB_YUREX is not set
++CONFIG_USB_GADGET=y
++CONFIG_USB_GADGET_DEBUG_FILES=y
++CONFIG_USB_GADGET_VBUS_DRAW=2
++CONFIG_USB_GADGET_SELECTED=y
++# CONFIG_USB_GADGET_FUSB300 is not set
++# CONFIG_USB_GADGET_R8A66597 is not set
++CONFIG_USB_GADGET_S3C2410=y
++CONFIG_USB_S3C2410=y
++# CONFIG_USB_S3C2410_DEBUG is not set
++# CONFIG_USB_GADGET_S3C_HSUDC is not set
++# CONFIG_USB_GADGET_PXA_U2O is not set
++# CONFIG_USB_GADGET_M66592 is not set
++# CONFIG_USB_GADGET_DUMMY_HCD is not set
++# CONFIG_USB_ZERO is not set
++# CONFIG_USB_AUDIO is not set
++# CONFIG_USB_ETH is not set
++# CONFIG_USB_G_NCM is not set
++# CONFIG_USB_GADGETFS is not set
++# CONFIG_USB_FUNCTIONFS is not set
++CONFIG_USB_FILE_STORAGE=m
++# CONFIG_USB_FILE_STORAGE_TEST is not set
++CONFIG_USB_MASS_STORAGE=m
++CONFIG_USB_G_SERIAL=m
++# CONFIG_USB_MIDI_GADGET is not set
++# CONFIG_USB_G_PRINTER is not set
++# CONFIG_USB_CDC_COMPOSITE is not set
++# CONFIG_USB_G_MULTI is not set
++# CONFIG_USB_G_HID is not set
++# CONFIG_USB_G_DBGP is not set
++# CONFIG_USB_G_WEBCAM is not set
++
++#
++# OTG and related infrastructure
++#
++# CONFIG_USB_GPIO_VBUS is not set
++# CONFIG_USB_ULPI is not set
++# CONFIG_NOP_USB_XCEIV is not set
++CONFIG_MMC=y
++# CONFIG_MMC_DEBUG is not set
++# CONFIG_MMC_UNSAFE_RESUME is not set
++# CONFIG_MMC_CLKGATE is not set
++
++#
++# MMC/SD/SDIO Card Drivers
++#
++CONFIG_MMC_BLOCK=y
++CONFIG_MMC_BLOCK_MINORS=8
++CONFIG_MMC_BLOCK_BOUNCE=y
++# CONFIG_SDIO_UART is not set
++# CONFIG_MMC_TEST is not set
++
++#
++# MMC/SD/SDIO Host Controller Drivers
++#
++# CONFIG_MMC_SDHCI is not set
++CONFIG_MMC_SPI=y
++CONFIG_MMC_S3C=y
++# CONFIG_MMC_S3C_HW_SDIO_IRQ is not set
++CONFIG_MMC_S3C_PIO=y
++# CONFIG_MMC_S3C_DMA is not set
++# CONFIG_MMC_S3C_PIODMA is not set
++# CONFIG_MMC_DW is not set
++# CONFIG_MMC_VUB300 is not set
++# CONFIG_MMC_USHC is not set
++# CONFIG_MEMSTICK is not set
++CONFIG_NEW_LEDS=y
++CONFIG_LEDS_CLASS=y
++
++#
++# LED drivers
++#
++# CONFIG_LEDS_LM3530 is not set
++CONFIG_LEDS_S3C24XX=m
++# CONFIG_LEDS_PCA9532 is not set
++# CONFIG_LEDS_GPIO is not set
++# CONFIG_LEDS_LP3944 is not set
++# CONFIG_LEDS_LP5521 is not set
++# CONFIG_LEDS_LP5523 is not set
++# CONFIG_LEDS_PCA955X is not set
++# CONFIG_LEDS_DAC124S085 is not set
++# CONFIG_LEDS_PWM is not set
++# CONFIG_LEDS_BD2802 is not set
++# CONFIG_LEDS_LT3593 is not set
++CONFIG_LEDS_TRIGGERS=y
++
++#
++# LED Triggers
++#
++CONFIG_LEDS_TRIGGER_TIMER=y
++CONFIG_LEDS_TRIGGER_HEARTBEAT=y
++# CONFIG_LEDS_TRIGGER_BACKLIGHT is not set
++# CONFIG_LEDS_TRIGGER_GPIO is not set
++# CONFIG_LEDS_TRIGGER_DEFAULT_ON is not set
++
++#
++# iptables trigger is under Netfilter config (LED target)
++#
++# CONFIG_NFC_DEVICES is not set
++# CONFIG_ACCESSIBILITY is not set
++CONFIG_RTC_LIB=y
++CONFIG_RTC_CLASS=y
++CONFIG_RTC_HCTOSYS=y
++CONFIG_RTC_HCTOSYS_DEVICE="rtc0"
++# CONFIG_RTC_DEBUG is not set
++
++#
++# RTC interfaces
++#
++CONFIG_RTC_INTF_SYSFS=y
++CONFIG_RTC_INTF_PROC=y
++CONFIG_RTC_INTF_DEV=y
++# CONFIG_RTC_INTF_DEV_UIE_EMUL is not set
++# CONFIG_RTC_DRV_TEST is not set
++
++#
++# I2C RTC drivers
++#
++CONFIG_RTC_DRV_DS1307=y
++# CONFIG_RTC_DRV_DS1374 is not set
++# CONFIG_RTC_DRV_DS1672 is not set
++# CONFIG_RTC_DRV_DS3232 is not set
++# CONFIG_RTC_DRV_MAX6900 is not set
++# CONFIG_RTC_DRV_RS5C372 is not set
++# CONFIG_RTC_DRV_ISL1208 is not set
++# CONFIG_RTC_DRV_ISL12022 is not set
++# CONFIG_RTC_DRV_X1205 is not set
++# CONFIG_RTC_DRV_PCF8563 is not set
++# CONFIG_RTC_DRV_PCF8583 is not set
++# CONFIG_RTC_DRV_M41T80 is not set
++# CONFIG_RTC_DRV_BQ32K is not set
++# CONFIG_RTC_DRV_S35390A is not set
++# CONFIG_RTC_DRV_FM3130 is not set
++# CONFIG_RTC_DRV_RX8581 is not set
++# CONFIG_RTC_DRV_RX8025 is not set
++# CONFIG_RTC_DRV_EM3027 is not set
++# CONFIG_RTC_DRV_RV3029C2 is not set
++
++#
++# SPI RTC drivers
++#
++# CONFIG_RTC_DRV_M41T93 is not set
++# CONFIG_RTC_DRV_M41T94 is not set
++# CONFIG_RTC_DRV_DS1305 is not set
++# CONFIG_RTC_DRV_DS1390 is not set
++# CONFIG_RTC_DRV_MAX6902 is not set
++# CONFIG_RTC_DRV_R9701 is not set
++# CONFIG_RTC_DRV_RS5C348 is not set
++# CONFIG_RTC_DRV_DS3234 is not set
++# CONFIG_RTC_DRV_PCF2123 is not set
++
++#
++# Platform RTC drivers
++#
++# CONFIG_RTC_DRV_CMOS is not set
++# CONFIG_RTC_DRV_DS1286 is not set
++# CONFIG_RTC_DRV_DS1511 is not set
++# CONFIG_RTC_DRV_DS1553 is not set
++# CONFIG_RTC_DRV_DS1742 is not set
++# CONFIG_RTC_DRV_STK17TA8 is not set
++# CONFIG_RTC_DRV_M48T86 is not set
++# CONFIG_RTC_DRV_M48T35 is not set
++# CONFIG_RTC_DRV_M48T59 is not set
++# CONFIG_RTC_DRV_MSM6242 is not set
++# CONFIG_RTC_DRV_BQ4802 is not set
++# CONFIG_RTC_DRV_RP5C01 is not set
++# CONFIG_RTC_DRV_V3020 is not set
++
++#
++# on-CPU RTC drivers
++#
++CONFIG_RTC_DRV_S3C=y
++# CONFIG_DMADEVICES is not set
++# CONFIG_AUXDISPLAY is not set
++# CONFIG_UIO is not set
++# CONFIG_STAGING is not set
++
++#
++# File systems
++#
++CONFIG_EXT2_FS=y
++# CONFIG_EXT2_FS_XATTR is not set
++# CONFIG_EXT2_FS_XIP is not set
++# CONFIG_EXT3_FS is not set
++# CONFIG_EXT4_FS is not set
++# CONFIG_REISERFS_FS is not set
++# CONFIG_JFS_FS is not set
++# CONFIG_XFS_FS is not set
++# CONFIG_OCFS2_FS is not set
++# CONFIG_BTRFS_FS is not set
++# CONFIG_NILFS2_FS is not set
++CONFIG_FS_POSIX_ACL=y
++CONFIG_FILE_LOCKING=y
++CONFIG_FSNOTIFY=y
++CONFIG_DNOTIFY=y
++CONFIG_INOTIFY_USER=y
++# CONFIG_FANOTIFY is not set
++# CONFIG_QUOTA is not set
++# CONFIG_QUOTACTL is not set
++# CONFIG_AUTOFS4_FS is not set
++# CONFIG_FUSE_FS is not set
++CONFIG_GENERIC_ACL=y
++
++#
++# Caches
++#
++# CONFIG_FSCACHE is not set
++
++#
++# CD-ROM/DVD Filesystems
++#
++# CONFIG_ISO9660_FS is not set
++# CONFIG_UDF_FS is not set
++
++#
++# DOS/FAT/NT Filesystems
++#
++CONFIG_FAT_FS=y
++CONFIG_MSDOS_FS=y
++CONFIG_VFAT_FS=y
++CONFIG_FAT_DEFAULT_CODEPAGE=437
++CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1"
++CONFIG_NTFS_FS=y
++# CONFIG_NTFS_DEBUG is not set
++CONFIG_NTFS_RW=y
++
++#
++# Pseudo filesystems
++#
++CONFIG_PROC_FS=y
++CONFIG_PROC_SYSCTL=y
++CONFIG_PROC_PAGE_MONITOR=y
++CONFIG_SYSFS=y
++CONFIG_TMPFS=y
++CONFIG_TMPFS_POSIX_ACL=y
++CONFIG_TMPFS_XATTR=y
++# CONFIG_HUGETLB_PAGE is not set
++CONFIG_CONFIGFS_FS=y
++CONFIG_MISC_FILESYSTEMS=y
++# CONFIG_ADFS_FS is not set
++# CONFIG_AFFS_FS is not set
++# CONFIG_ECRYPT_FS is not set
++# CONFIG_HFS_FS is not set
++# CONFIG_HFSPLUS_FS is not set
++# CONFIG_BEFS_FS is not set
++# CONFIG_BFS_FS is not set
++# CONFIG_EFS_FS is not set
++CONFIG_JFFS2_FS=y
++CONFIG_JFFS2_FS_DEBUG=0
++CONFIG_JFFS2_FS_WRITEBUFFER=y
++# CONFIG_JFFS2_FS_WBUF_VERIFY is not set
++CONFIG_JFFS2_SUMMARY=y
++# CONFIG_JFFS2_FS_XATTR is not set
++# CONFIG_JFFS2_COMPRESSION_OPTIONS is not set
++CONFIG_JFFS2_ZLIB=y
++# CONFIG_JFFS2_LZO is not set
++CONFIG_JFFS2_RTIME=y
++# CONFIG_JFFS2_RUBIN is not set
++CONFIG_UBIFS_FS=y
++CONFIG_UBIFS_FS_XATTR=y
++CONFIG_UBIFS_FS_ADVANCED_COMPR=y
++CONFIG_UBIFS_FS_LZO=y
++CONFIG_UBIFS_FS_ZLIB=y
++# CONFIG_UBIFS_FS_DEBUG is not set
++# CONFIG_LOGFS is not set
++CONFIG_CRAMFS=y
++# CONFIG_SQUASHFS is not set
++# CONFIG_VXFS_FS is not set
++# CONFIG_MINIX_FS is not set
++# CONFIG_OMFS_FS is not set
++# CONFIG_HPFS_FS is not set
++# CONFIG_QNX4FS_FS is not set
++# CONFIG_ROMFS_FS is not set
++# CONFIG_PSTORE is not set
++# CONFIG_SYSV_FS is not set
++# CONFIG_UFS_FS is not set
++CONFIG_NETWORK_FILESYSTEMS=y
++CONFIG_NFS_FS=y
++CONFIG_NFS_V3=y
++CONFIG_NFS_V3_ACL=y
++CONFIG_NFS_V4=y
++# CONFIG_NFS_V4_1 is not set
++CONFIG_ROOT_NFS=y
++# CONFIG_NFS_USE_LEGACY_DNS is not set
++CONFIG_NFS_USE_KERNEL_DNS=y
++# CONFIG_NFS_USE_NEW_IDMAPPER is not set
++# CONFIG_NFSD is not set
++CONFIG_LOCKD=y
++CONFIG_LOCKD_V4=y
++CONFIG_NFS_ACL_SUPPORT=y
++CONFIG_NFS_COMMON=y
++CONFIG_SUNRPC=y
++CONFIG_SUNRPC_GSS=y
++# CONFIG_CEPH_FS is not set
++# CONFIG_CIFS is not set
++# CONFIG_NCP_FS is not set
++# CONFIG_CODA_FS is not set
++# CONFIG_AFS_FS is not set
++
++#
++# Partition Types
++#
++CONFIG_PARTITION_ADVANCED=y
++# CONFIG_ACORN_PARTITION is not set
++# CONFIG_OSF_PARTITION is not set
++# CONFIG_AMIGA_PARTITION is not set
++# CONFIG_ATARI_PARTITION is not set
++# CONFIG_MAC_PARTITION is not set
++CONFIG_MSDOS_PARTITION=y
++CONFIG_BSD_DISKLABEL=y
++# CONFIG_MINIX_SUBPARTITION is not set
++CONFIG_SOLARIS_X86_PARTITION=y
++# CONFIG_UNIXWARE_DISKLABEL is not set
++# CONFIG_LDM_PARTITION is not set
++# CONFIG_SGI_PARTITION is not set
++# CONFIG_ULTRIX_PARTITION is not set
++# CONFIG_SUN_PARTITION is not set
++# CONFIG_KARMA_PARTITION is not set
++# CONFIG_EFI_PARTITION is not set
++# CONFIG_SYSV68_PARTITION is not set
++CONFIG_NLS=y
++CONFIG_NLS_DEFAULT="iso8859-1"
++CONFIG_NLS_CODEPAGE_437=y
++# CONFIG_NLS_CODEPAGE_737 is not set
++# CONFIG_NLS_CODEPAGE_775 is not set
++# CONFIG_NLS_CODEPAGE_850 is not set
++# CONFIG_NLS_CODEPAGE_852 is not set
++# CONFIG_NLS_CODEPAGE_855 is not set
++# CONFIG_NLS_CODEPAGE_857 is not set
++# CONFIG_NLS_CODEPAGE_860 is not set
++# CONFIG_NLS_CODEPAGE_861 is not set
++# CONFIG_NLS_CODEPAGE_862 is not set
++# CONFIG_NLS_CODEPAGE_863 is not set
++# CONFIG_NLS_CODEPAGE_864 is not set
++# CONFIG_NLS_CODEPAGE_865 is not set
++# CONFIG_NLS_CODEPAGE_866 is not set
++# CONFIG_NLS_CODEPAGE_869 is not set
++# CONFIG_NLS_CODEPAGE_936 is not set
++# CONFIG_NLS_CODEPAGE_950 is not set
++# CONFIG_NLS_CODEPAGE_932 is not set
++# CONFIG_NLS_CODEPAGE_949 is not set
++# CONFIG_NLS_CODEPAGE_874 is not set
++# CONFIG_NLS_ISO8859_8 is not set
++# CONFIG_NLS_CODEPAGE_1250 is not set
++# CONFIG_NLS_CODEPAGE_1251 is not set
++CONFIG_NLS_ASCII=y
++CONFIG_NLS_ISO8859_1=y
++# CONFIG_NLS_ISO8859_2 is not set
++# CONFIG_NLS_ISO8859_3 is not set
++# CONFIG_NLS_ISO8859_4 is not set
++# CONFIG_NLS_ISO8859_5 is not set
++# CONFIG_NLS_ISO8859_6 is not set
++# CONFIG_NLS_ISO8859_7 is not set
++# CONFIG_NLS_ISO8859_9 is not set
++# CONFIG_NLS_ISO8859_13 is not set
++# CONFIG_NLS_ISO8859_14 is not set
++# CONFIG_NLS_ISO8859_15 is not set
++# CONFIG_NLS_KOI8_R is not set
++# CONFIG_NLS_KOI8_U is not set
++CONFIG_NLS_UTF8=y
++# CONFIG_DLM is not set
++
++#
++# Kernel hacking
++#
++# CONFIG_PRINTK_TIME is not set
++CONFIG_DEFAULT_MESSAGE_LOGLEVEL=4
++# CONFIG_ENABLE_WARN_DEPRECATED is not set
++# CONFIG_ENABLE_MUST_CHECK is not set
++CONFIG_FRAME_WARN=1024
++# CONFIG_MAGIC_SYSRQ is not set
++# CONFIG_STRIP_ASM_SYMS is not set
++# CONFIG_UNUSED_SYMBOLS is not set
++# CONFIG_DEBUG_FS is not set
++# CONFIG_HEADERS_CHECK is not set
++# CONFIG_DEBUG_SECTION_MISMATCH is not set
++# CONFIG_DEBUG_KERNEL is not set
++# CONFIG_HARDLOCKUP_DETECTOR is not set
++# CONFIG_SPARSE_RCU_POINTER is not set
++CONFIG_DEBUG_BUGVERBOSE=y
++# CONFIG_DEBUG_MEMORY_INIT is not set
++CONFIG_FRAME_POINTER=y
++# CONFIG_SYSCTL_SYSCALL_CHECK is not set
++CONFIG_HAVE_FUNCTION_TRACER=y
++CONFIG_HAVE_FUNCTION_GRAPH_TRACER=y
++CONFIG_HAVE_DYNAMIC_FTRACE=y
++CONFIG_HAVE_FTRACE_MCOUNT_RECORD=y
++CONFIG_HAVE_C_RECORDMCOUNT=y
++CONFIG_TRACING_SUPPORT=y
++# CONFIG_FTRACE is not set
++# CONFIG_DMA_API_DEBUG is not set
++# CONFIG_ATOMIC64_SELFTEST is not set
++# CONFIG_SAMPLES is not set
++CONFIG_HAVE_ARCH_KGDB=y
++# CONFIG_TEST_KSTRTOX is not set
++# CONFIG_STRICT_DEVMEM is not set
++# CONFIG_ARM_UNWIND is not set
++# CONFIG_DEBUG_USER is not set
++# CONFIG_OC_ETM is not set
++CONFIG_DEBUG_S3C_UART=0
++
++#
++# Security options
++#
++CONFIG_KEYS=y
++# CONFIG_KEYS_DEBUG_PROC_KEYS is not set
++# CONFIG_SECURITY_DMESG_RESTRICT is not set
++# CONFIG_SECURITY is not set
++# CONFIG_SECURITYFS is not set
++CONFIG_DEFAULT_SECURITY_DAC=y
++CONFIG_DEFAULT_SECURITY=""
++CONFIG_CRYPTO=y
++
++#
++# Crypto core or helper
++#
++CONFIG_CRYPTO_ALGAPI=y
++CONFIG_CRYPTO_ALGAPI2=y
++CONFIG_CRYPTO_AEAD2=y
++CONFIG_CRYPTO_BLKCIPHER=y
++CONFIG_CRYPTO_BLKCIPHER2=y
++CONFIG_CRYPTO_HASH=y
++CONFIG_CRYPTO_HASH2=y
++CONFIG_CRYPTO_RNG2=y
++CONFIG_CRYPTO_PCOMP2=y
++CONFIG_CRYPTO_MANAGER=y
++CONFIG_CRYPTO_MANAGER2=y
++CONFIG_CRYPTO_MANAGER_DISABLE_TESTS=y
++# CONFIG_CRYPTO_GF128MUL is not set
++# CONFIG_CRYPTO_NULL is not set
++CONFIG_CRYPTO_WORKQUEUE=y
++# CONFIG_CRYPTO_CRYPTD is not set
++# CONFIG_CRYPTO_AUTHENC is not set
++# CONFIG_CRYPTO_TEST is not set
++
++#
++# Authenticated Encryption with Associated Data
++#
++# CONFIG_CRYPTO_CCM is not set
++# CONFIG_CRYPTO_GCM is not set
++# CONFIG_CRYPTO_SEQIV is not set
++
++#
++# Block modes
++#
++# CONFIG_CRYPTO_CBC is not set
++# CONFIG_CRYPTO_CTR is not set
++# CONFIG_CRYPTO_CTS is not set
++CONFIG_CRYPTO_ECB=y
++# CONFIG_CRYPTO_LRW is not set
++# CONFIG_CRYPTO_PCBC is not set
++# CONFIG_CRYPTO_XTS is not set
++
++#
++# Hash modes
++#
++# CONFIG_CRYPTO_HMAC is not set
++# CONFIG_CRYPTO_XCBC is not set
++# CONFIG_CRYPTO_VMAC is not set
++
++#
++# Digest
++#
++CONFIG_CRYPTO_CRC32C=y
++# CONFIG_CRYPTO_GHASH is not set
++# CONFIG_CRYPTO_MD4 is not set
++# CONFIG_CRYPTO_MD5 is not set
++# CONFIG_CRYPTO_MICHAEL_MIC is not set
++# CONFIG_CRYPTO_RMD128 is not set
++# CONFIG_CRYPTO_RMD160 is not set
++# CONFIG_CRYPTO_RMD256 is not set
++# CONFIG_CRYPTO_RMD320 is not set
++CONFIG_CRYPTO_SHA1=y
++# CONFIG_CRYPTO_SHA256 is not set
++# CONFIG_CRYPTO_SHA512 is not set
++# CONFIG_CRYPTO_TGR192 is not set
++# CONFIG_CRYPTO_WP512 is not set
++
++#
++# Ciphers
++#
++CONFIG_CRYPTO_AES=y
++# CONFIG_CRYPTO_ANUBIS is not set
++CONFIG_CRYPTO_ARC4=y
++# CONFIG_CRYPTO_BLOWFISH is not set
++# CONFIG_CRYPTO_CAMELLIA is not set
++# CONFIG_CRYPTO_CAST5 is not set
++# CONFIG_CRYPTO_CAST6 is not set
++# CONFIG_CRYPTO_DES is not set
++# CONFIG_CRYPTO_FCRYPT is not set
++# CONFIG_CRYPTO_KHAZAD is not set
++# CONFIG_CRYPTO_SALSA20 is not set
++# CONFIG_CRYPTO_SEED is not set
++# CONFIG_CRYPTO_SERPENT is not set
++# CONFIG_CRYPTO_TEA is not set
++# CONFIG_CRYPTO_TWOFISH is not set
++
++#
++# Compression
++#
++CONFIG_CRYPTO_DEFLATE=y
++# CONFIG_CRYPTO_ZLIB is not set
++CONFIG_CRYPTO_LZO=y
++
++#
++# Random Number Generation
++#
++# CONFIG_CRYPTO_ANSI_CPRNG is not set
++# CONFIG_CRYPTO_USER_API_HASH is not set
++# CONFIG_CRYPTO_USER_API_SKCIPHER is not set
++# CONFIG_CRYPTO_HW is not set
++# CONFIG_BINARY_PRINTF is not set
++
++#
++# Library routines
++#
++CONFIG_BITREVERSE=y
++CONFIG_CRC_CCITT=y
++CONFIG_CRC16=y
++# CONFIG_CRC_T10DIF is not set
++CONFIG_CRC_ITU_T=y
++CONFIG_CRC32=y
++CONFIG_CRC7=y
++CONFIG_LIBCRC32C=y
++CONFIG_ZLIB_INFLATE=y
++CONFIG_ZLIB_DEFLATE=y
++CONFIG_LZO_COMPRESS=y
++CONFIG_LZO_DECOMPRESS=y
++# CONFIG_XZ_DEC is not set
++# CONFIG_XZ_DEC_BCJ is not set
++CONFIG_TEXTSEARCH=y
++CONFIG_TEXTSEARCH_KMP=y
++CONFIG_TEXTSEARCH_BM=y
++CONFIG_TEXTSEARCH_FSM=y
++CONFIG_HAS_IOMEM=y
++CONFIG_HAS_DMA=y
++CONFIG_NLATTR=y
++CONFIG_GENERIC_ATOMIC64=y
++CONFIG_AVERAGE=y
+diff -Nuar -x .gitignore linux-3.0/drivers/input/touchscreen/s3c2410_ts.c linux-3.0-fl2440/drivers/input/touchscreen/s3c2410_ts.c
+--- linux-3.0/drivers/input/touchscreen/s3c2410_ts.c	2011-07-22 10:17:23.000000000 +0800
++++ linux-3.0-fl2440/drivers/input/touchscreen/s3c2410_ts.c	2020-01-09 16:54:31.277380204 +0800
+@@ -126,6 +126,7 @@
+ 			input_report_abs(ts.input, ABS_Y, ts.yp);
+ 
+ 			input_report_key(ts.input, BTN_TOUCH, 1);
++            input_report_abs(ts.input, ABS_PRESSURE, 1); /* Add by guowenxue, 2012.03.30 */
+ 			input_sync(ts.input);
+ 
+ 			ts.xp = 0;
+@@ -140,6 +141,7 @@
+ 		ts.count = 0;
+ 
+ 		input_report_key(ts.input, BTN_TOUCH, 0);
++        input_report_abs(ts.input, ABS_PRESSURE, 0); /* Add by guowenxue, 2012.03.30 */
+ 		input_sync(ts.input);
+ 
+ 		writel(WAIT4INT | INT_DOWN, ts.io + S3C2410_ADCTSC);
+@@ -314,10 +316,11 @@
+ 	}
+ 
+ 	ts.input = input_dev;
+-	ts.input->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS);
++	ts.input->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS) | BIT(EV_SYN); /* Modify by guowenxue, 2012.03.30 */
+ 	ts.input->keybit[BIT_WORD(BTN_TOUCH)] = BIT_MASK(BTN_TOUCH);
+ 	input_set_abs_params(ts.input, ABS_X, 0, 0x3FF, 0, 0);
+ 	input_set_abs_params(ts.input, ABS_Y, 0, 0x3FF, 0, 0);
++    input_set_abs_params(ts.input, ABS_PRESSURE, 0, 1, 0, 0);  /* Add by guowenxue, 2012.03.30 */
+ 
+ 	ts.input->name = "S3C24XX TouchScreen";
+ 	ts.input->id.bustype = BUS_HOST;
+diff -Nuar -x .gitignore linux-3.0/drivers/mmc/host/s3cmci.c linux-3.0-fl2440/drivers/mmc/host/s3cmci.c
+--- linux-3.0/drivers/mmc/host/s3cmci.c	2011-07-22 10:17:23.000000000 +0800
++++ linux-3.0-fl2440/drivers/mmc/host/s3cmci.c	2020-01-09 16:54:31.277380204 +0800
+@@ -1275,6 +1275,7 @@
+ 
+ 	writel(mci_con, host->base + S3C2410_SDICON);
+ 
++#if 0 /*Comment by guowenxue, remove the noisy debug output*/
+ 	if ((ios->power_mode == MMC_POWER_ON) ||
+ 	    (ios->power_mode == MMC_POWER_UP)) {
+ 		dbg(host, dbg_conf, "running at %lukHz (requested: %ukHz).\n",
+@@ -1282,6 +1283,7 @@
+ 	} else {
+ 		dbg(host, dbg_conf, "powered down.\n");
+ 	}
++#endif
+ 
+ 	host->bus_width = ios->bus_width;
+ }
+@@ -1357,11 +1359,16 @@
+ 	.enable_sdio_irq = s3cmci_enable_sdio_irq,
+ };
+ 
++/*Change s3cmci_def_pdata by guowenxue, 2011.09.06*/
+ static struct s3c24xx_mci_pdata s3cmci_def_pdata = {
+ 	/* This is currently here to avoid a number of if (host->pdata)
+ 	 * checks. Any zero fields to ensure reasonable defaults are picked. */
+-	 .no_wprotect = 1,
+-	 .no_detect = 1,
++     .gpio_detect = S3C2410_GPG(10), /* NCD(NCD_SD) pin use EINT18/GPG10*/
++     .gpio_wprotect = S3C2410_GPH(8), /*WP(WP_SD) pin use GPH8*/
++     .ocr_avail = MMC_VDD_32_33|MMC_VDD_33_34,
++     .wprotect_invert = 0,
++     .detect_invert = 0,
++     .set_power = NULL,
+ };
+ 
+ #ifdef CONFIG_CPU_FREQ
+diff -Nuar -x .gitignore linux-3.0/drivers/net/dm9000.c linux-3.0-fl2440/drivers/net/dm9000.c
+--- linux-3.0/drivers/net/dm9000.c	2011-07-22 10:17:23.000000000 +0800
++++ linux-3.0-fl2440/drivers/net/dm9000.c	2020-01-09 16:54:31.277380204 +0800
+@@ -39,6 +39,10 @@
+ #include <asm/irq.h>
+ #include <asm/io.h>
+ 
++#include <mach/regs-gpio.h>   //add by guowenxue, 2011.08.30
++#include <mach/irqs.h>
++#include <mach/hardware.h>
++
+ #include "dm9000.h"
+ 
+ /* Board/System/Debug information/definition ---------------- */
+@@ -1144,7 +1148,12 @@
+ dm9000_open(struct net_device *dev)
+ {
+ 	board_info_t *db = netdev_priv(dev);
+-	unsigned long irqflags = db->irq_res->flags & IRQF_TRIGGER_MASK;
++	unsigned long  irqflags;
++
++    /* Modified by guowenxue, 2011.08.30 */
++    db->irq_res->flags |= IRQ_TYPE_EDGE_RISING;   
++    irqflags = db->irq_res->flags & IRQF_TRIGGER_MASK;
++    irq_set_irq_type(dev->irq, IRQ_TYPE_EDGE_RISING);
+ 
+ 	if (netif_msg_ifup(db))
+ 		dev_dbg(db->dev, "enabling %s\n", dev->name);
+diff -Nuar -x .gitignore linux-3.0/drivers/tty/serial/samsung.c linux-3.0-fl2440/drivers/tty/serial/samsung.c
+--- linux-3.0/drivers/tty/serial/samsung.c	2011-07-22 10:17:23.000000000 +0800
++++ linux-3.0-fl2440/drivers/tty/serial/samsung.c	2020-01-09 16:54:31.297380204 +0800
+@@ -54,7 +54,7 @@
+ 
+ /* UART name and device definitions */
+ 
+-#define S3C24XX_SERIAL_NAME	"ttySAC"
++#define S3C24XX_SERIAL_NAME	"ttyS" /*Modified by guowenxue, 2011.08.30*/
+ #define S3C24XX_SERIAL_MAJOR	204
+ #define S3C24XX_SERIAL_MINOR	64
+ 
+@@ -882,7 +882,7 @@
+ 
+ static struct uart_driver s3c24xx_uart_drv = {
+ 	.owner		= THIS_MODULE,
+-	.driver_name	= "s3c2410_serial",
++	.driver_name	= "ttyS", /*Modified by guowenxue, 2011.08.30*/
+ 	.nr		= CONFIG_SERIAL_SAMSUNG_UARTS,
+ 	.cons		= S3C24XX_SERIAL_CONSOLE,
+ 	.dev_name	= S3C24XX_SERIAL_NAME,
+diff -Nuar -x .gitignore linux-3.0/drivers/tty/vt/vt.c linux-3.0-fl2440/drivers/tty/vt/vt.c
+--- linux-3.0/drivers/tty/vt/vt.c	2011-07-22 10:17:23.000000000 +0800
++++ linux-3.0-fl2440/drivers/tty/vt/vt.c	2020-01-09 16:54:31.297380204 +0800
+@@ -3843,12 +3843,14 @@
+  */
+ static void blank_screen_t(unsigned long dummy)
+ {
++#if 0 /* Comment by guowenxue, don't shutdown the LCD  */
+ 	if (unlikely(!keventd_up())) {
+ 		mod_timer(&console_timer, jiffies + (blankinterval * HZ));
+ 		return;
+ 	}
+ 	blank_timer_expired = 1;
+ 	schedule_work(&console_work);
++#endif
+ }
+ 
+ void poke_blanked_console(void)
+diff -Nuar -x .gitignore linux-3.0/drivers/usb/host/ohci-s3c2410.c linux-3.0-fl2440/drivers/usb/host/ohci-s3c2410.c
+--- linux-3.0/drivers/usb/host/ohci-s3c2410.c	2011-07-22 10:17:23.000000000 +0800
++++ linux-3.0-fl2440/drivers/usb/host/ohci-s3c2410.c	2020-01-09 16:54:31.297380204 +0800
+@@ -22,6 +22,7 @@
+ #include <linux/platform_device.h>
+ #include <linux/clk.h>
+ #include <plat/usb-control.h>
++#include <mach/regs-clock.h> /* Add by guowenxue, 2012.04.01 */
+ 
+ #define valid_port(idx) ((idx) == 1 || (idx) == 2)
+ 
+@@ -45,6 +46,15 @@
+ {
+ 	struct s3c2410_hcd_info *info = dev->dev.platform_data;
+ 
++	/* Add by guowenxue 2012.04.01, fix device descriptor read/64, error -62 bug, value refer to datasheet P255 */
++	unsigned long upllvalue = (0x38<<12)|(0x02<<4)|(0x02);
++	while (upllvalue != __raw_readl(S3C2410_UPLLCON))
++	{ 
++		__raw_writel(upllvalue, S3C2410_UPLLCON); 
++		mdelay(1); 
++	}
++	__raw_writel(upllvalue, S3C2410_UPLLCON);
++
+ 	dev_dbg(&dev->dev, "s3c2410_start_hc:\n");
+ 
+ 	clk_enable(usb_clk);
+diff -Nuar -x .gitignore linux-3.0/drivers/usb/serial/Kconfig linux-3.0-fl2440/drivers/usb/serial/Kconfig
+--- linux-3.0/drivers/usb/serial/Kconfig	2011-07-22 10:17:23.000000000 +0800
++++ linux-3.0-fl2440/drivers/usb/serial/Kconfig	2020-01-09 16:54:31.297380204 +0800
+@@ -588,7 +588,8 @@
+ 	  module will be called keyspan_pda.
+ 
+ config USB_SERIAL_WWAN
+-	tristate
++    boolean
++    default y if USB_SERIAL_OPTION
+ 
+ config USB_SERIAL_OPTION
+ 	tristate "USB driver for GSM and CDMA modems"
+diff -Nuar -x .gitignore linux-3.0/drivers/usb/serial/option.c linux-3.0-fl2440/drivers/usb/serial/option.c
+--- linux-3.0/drivers/usb/serial/option.c	2011-07-22 10:17:23.000000000 +0800
++++ linux-3.0-fl2440/drivers/usb/serial/option.c	2020-01-09 16:54:31.301380204 +0800
+@@ -51,6 +51,13 @@
+ static void option_instat_callback(struct urb *urb);
+ 
+ /* Vendor and product IDs */
++static int vendor = 0; /*   Add by guowenxue */
++static int product = 0; /*   Add by guowenxue  */
++
++/*   Vendor and product IDs */
++#define OPTION_VENDOR_RESERVED      0xFFFF /*   Add by guowenxue */
++#define OPTION_RESERVED_DEVICE      0xFFFF /*   Add by guowenxue */ 
++
+ #define OPTION_VENDOR_ID			0x0AF0
+ #define OPTION_PRODUCT_COLT			0x5000
+ #define OPTION_PRODUCT_RICOLA			0x6000
+@@ -446,7 +453,8 @@
+ 	.reason = OPTION_BLACKLIST_SENDSETUP
+ };
+ 
+-static const struct usb_device_id option_ids[] = {
++static struct usb_device_id option_ids[] = {
++    { USB_DEVICE(OPTION_VENDOR_RESERVED, OPTION_RESERVED_DEVICE) }, /*   Add by guowenxue */
+ 	{ USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_COLT) },
+ 	{ USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_RICOLA) },
+ 	{ USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_RICOLA_LIGHT) },
+@@ -633,6 +641,7 @@
+ 	{ USB_DEVICE(KYOCERA_VENDOR_ID, KYOCERA_PRODUCT_KPC650) },
+ 	{ USB_DEVICE(KYOCERA_VENDOR_ID, KYOCERA_PRODUCT_KPC680) },
+ 	{ USB_DEVICE(QUALCOMM_VENDOR_ID, 0x6000)}, /* ZTE AC8700 */
++	{ USB_DEVICE(QUALCOMM_VENDOR_ID, 0x9000)}, /* ZTE AC8700 */
+ 	{ USB_DEVICE(QUALCOMM_VENDOR_ID, 0x6613)}, /* Onda H600/ZTE MF330 */
+ 	{ USB_DEVICE(CMOTECH_VENDOR_ID, CMOTECH_PRODUCT_6280) }, /* BP3-USB & BP3-EXT HSDPA */
+ 	{ USB_DEVICE(CMOTECH_VENDOR_ID, CMOTECH_PRODUCT_6008) },
+@@ -1079,6 +1088,15 @@
+ static int __init option_init(void)
+ {
+ 	int retval;
++
++    if ((vendor>0) && (product>0))
++    {
++        option_ids[0].match_flags = USB_DEVICE_ID_MATCH_DEVICE;
++        option_ids[0].idVendor = vendor;
++        option_ids[0].idProduct = product;
++        printk("Register option drvier for modem vendor=0x%04x product=0x%04x\n", vendor, product);
++    }
++
+ 	retval = usb_serial_register(&option_1port_device);
+ 	if (retval)
+ 		goto failed_1port_device_register;
+@@ -1252,6 +1270,12 @@
+ 		0x22, 0x21, val, ifNum, NULL, 0, USB_CTRL_SET_TIMEOUT);
+ }
+ 
++/*  vendor and product option add by guowenxue  */
++module_param(vendor, int, S_IRUGO | S_IWUSR);
++MODULE_PARM_DESC(vendor, "User specified vendor ID");
++module_param(product, int, S_IRUGO | S_IWUSR);
++MODULE_PARM_DESC(product, "User specified product ID");
++
+ MODULE_AUTHOR(DRIVER_AUTHOR);
+ MODULE_DESCRIPTION(DRIVER_DESC);
+ MODULE_VERSION(DRIVER_VERSION);
+diff -Nuar -x .gitignore linux-3.0/Makefile linux-3.0-fl2440/Makefile
+--- linux-3.0/Makefile	2011-07-22 10:17:23.000000000 +0800
++++ linux-3.0-fl2440/Makefile	2020-01-09 17:26:42.517417250 +0800
+@@ -144,7 +144,7 @@
+ # but instead _all depend on modules
+ PHONY += all
+ ifeq ($(KBUILD_EXTMOD),)
+-_all: all
++_all: all 
+ else
+ _all: modules
+ endif
+@@ -192,8 +192,8 @@
+ # Default value for CROSS_COMPILE is not to prefix executables
+ # Note: Some architectures assign CROSS_COMPILE in their arch/*/Makefile
+ export KBUILD_BUILDHOST := $(SUBARCH)
+-ARCH		?= $(SUBARCH)
+-CROSS_COMPILE	?= $(CONFIG_CROSS_COMPILE:"%"=%)
++ARCH			?=  arm
++CROSS_COMPILE	?=  /opt/xtools/arm920t/bin/arm-linux-
+ 
+ # Architecture as present in compile.h
+ UTS_MACHINE 	:= $(ARCH)
+@@ -557,6 +557,8 @@
+ # This allow a user to issue only 'make' to build a kernel including modules
+ # Defaults to vmlinux, but the arch makefile usually adds further targets
+ all: vmlinux
++	mkimage -A arm -O linux -T kernel -C none -a 30008000 -e 30008040 -n "Linux Kernel" -d arch/arm/boot/zImage linuxrom-fl2440.bin
++	chmod a+x linuxrom-fl2440.bin
+ 
+ ifdef CONFIG_CC_OPTIMIZE_FOR_SIZE
+ KBUILD_CFLAGS	+= -Os
+@@ -1201,6 +1203,7 @@
+ 		-o -name '.*.rej' -o -size 0 \
+ 		-o -name '*%' -o -name '.*.cmd' -o -name 'core' \) \
+ 		-type f -print | xargs rm -f
++	@rm -f linuxrom-*.bin
+ 
+ 
+ # Packaging of the kernel to various formats
+diff -Nuar -x .gitignore linux-3.0/net/wireless/db.txt linux-3.0-fl2440/net/wireless/db.txt
+--- linux-3.0/net/wireless/db.txt	2011-07-22 10:17:23.000000000 +0800
++++ linux-3.0-fl2440/net/wireless/db.txt	2020-01-09 16:54:31.301380204 +0800
+@@ -1,17 +1,793 @@
+-#
+-# This file is a placeholder to prevent accidental build breakage if someone
+-# enables CONFIG_CFG80211_INTERNAL_REGDB.  Almost no one actually needs to
+-# enable that build option.
+-#
+-# You should be using CRDA instead.  It is even better if you use the CRDA
+-# package provided by your distribution, since they will probably keep it
+-# up-to-date on your behalf.
+-#
+-# If you _really_ intend to use CONFIG_CFG80211_INTERNAL_REGDB then you will
+-# need to replace this file with one containing appropriately formatted
+-# regulatory rules that cover the regulatory domains you will be using.  Your
+-# best option is to extract the db.txt file from the wireless-regdb git
+-# repository:
+-#
+-#   git://git.kernel.org/pub/scm/linux/kernel/git/linville/wireless-regdb.git
+-#
++# This is the world regulatory domain
++country 00:
++	(2402 - 2472 @ 40), (3, 20)
++        # Channel 12 - 13.
++        (2457 - 2482 @ 40), (3, 20), PASSIVE-SCAN, NO-IBSS
++        # Channel 14. Only JP enables this and for 802.11b only
++        (2474 - 2494 @ 20), (3, 20), PASSIVE-SCAN, NO-IBSS, NO-OFDM
++        # Channel 36 - 48
++        (5170 - 5250 @ 40), (3, 20), PASSIVE-SCAN, NO-IBSS
++        # NB: 5260 MHz - 5700 MHz requies DFS
++        # Channel 149 - 165
++        (5735 - 5835 @ 40), (3, 20), PASSIVE-SCAN, NO-IBSS
++
++
++country AD:
++        # 60 gHz band channels 1-4, ref: Etsi En 302 567
++        (57240 - 65880 @ 2160), (N/A, 40), NO-OUTDOOR
++
++country AE:
++	(2402 - 2482 @ 40), (N/A, 20)
++	(5170 - 5250 @ 40), (N/A, 20)
++	(5250 - 5330 @ 40), (N/A, 20), DFS
++	(5490 - 5710 @ 40), (N/A, 27), DFS
++
++country AL:
++	(2402 - 2482 @ 20), (N/A, 20)
++
++country AM:
++	(2402 - 2482 @ 40), (N/A, 20)
++	(5170 - 5250 @ 20), (N/A, 18)
++	(5250 - 5330 @ 20), (N/A, 18), DFS
++
++country AN:
++	(2402 - 2482 @ 40), (N/A, 20)
++	(5170 - 5250 @ 40), (N/A, 20)
++	(5250 - 5330 @ 40), (N/A, 20), DFS
++	(5490 - 5710 @ 40), (N/A, 27), DFS
++
++country AR:
++	(2402 - 2482 @ 40), (N/A, 20)
++	(5170 - 5250 @ 40), (3, 17)
++	(5250 - 5330 @ 40), (3, 20), DFS
++	(5490 - 5710 @ 40), (3, 20), DFS
++	(5735 - 5835 @ 40), (3, 30)
++
++country AT: DFS-ETSI
++	(2402 - 2482 @ 40), (N/A, 20)
++	(5170 - 5250 @ 40), (N/A, 20)
++	(5250 - 5330 @ 40), (N/A, 20), DFS
++	(5490 - 5710 @ 40), (N/A, 27), DFS
++        # 60 gHz band channels 1-4, ref: Etsi En 302 567
++        (57240 - 65880 @ 2160), (N/A, 40), NO-OUTDOOR
++
++country AU:
++	(2402 - 2482 @ 40), (N/A, 20)
++	(5170 - 5250 @ 40), (3, 23)
++	(5250 - 5330 @ 40), (3, 23), DFS
++	(5735 - 5835 @ 40), (3, 30)
++
++country AW:
++	(2402 - 2482 @ 40), (N/A, 20)
++	(5170 - 5250 @ 40), (N/A, 20)
++	(5250 - 5330 @ 40), (N/A, 20), DFS
++	(5490 - 5710 @ 40), (N/A, 27), DFS
++
++country AZ:
++	(2402 - 2482 @ 40), (N/A, 20)
++	(5170 - 5250 @ 40), (N/A, 18)
++	(5250 - 5330 @ 40), (N/A, 18), DFS
++
++country BA: DFS-ETSI
++	(2402 - 2482 @ 40), (N/A, 20)
++	(5170 - 5250 @ 40), (N/A, 20)
++	(5250 - 5330 @ 40), (N/A, 20), DFS
++	(5490 - 5710 @ 40), (N/A, 27), DFS
++        # 60 gHz band channels 1-4, ref: Etsi En 302 567
++        (57240 - 65880 @ 2160), (N/A, 40), NO-OUTDOOR
++
++country BB:
++	(2402 - 2482 @ 40), (N/A, 20)
++	(5170 - 5250 @ 40), (3, 23)
++	(5250 - 5330 @ 40), (3, 23), DFS
++	(5735 - 5835 @ 40), (3, 30)
++
++country BD:
++	(2402 - 2482 @ 40), (N/A, 20)
++
++country BE: DFS-ETSI
++	(2402 - 2482 @ 40), (N/A, 20)
++	(5170 - 5250 @ 40), (N/A, 20)
++	(5250 - 5330 @ 40), (N/A, 20), DFS
++	(5490 - 5710 @ 40), (N/A, 27), DFS
++        # 60 gHz band channels 1-4, ref: Etsi En 302 567
++        (57240 - 65880 @ 2160), (N/A, 40), NO-OUTDOOR
++
++country BG: DFS-ETSI
++	(2402 - 2482 @ 40), (N/A, 20)
++	(5170 - 5250 @ 40), (N/A, 23)
++	(5250 - 5290 @ 40), (N/A, 23), DFS
++	(5490 - 5710 @ 40), (N/A, 30), DFS
++        # 60 gHz band channels 1-4, ref: Etsi En 302 567
++        (57240 - 65880 @ 2160), (N/A, 40), NO-OUTDOOR
++
++country BH:
++	(2402 - 2482 @ 40), (N/A, 20)
++	(5170 - 5250 @ 20), (N/A, 20)
++	(5250 - 5330 @ 20), (N/A, 20), DFS
++	(5735 - 5835 @ 20), (N/A, 20)
++
++country BL:
++	(2402 - 2482 @ 40), (N/A, 20)
++	(5170 - 5250 @ 40), (N/A, 18)
++	(5250 - 5330 @ 40), (N/A, 18), DFS
++
++country BN:
++	(2402 - 2482 @ 40), (N/A, 20)
++	(5170 - 5250 @ 40), (N/A, 20)
++	(5250 - 5330 @ 40), (N/A, 20), DFS
++	(5735 - 5835 @ 40), (N/A, 30)
++
++country BO:
++	(2402 - 2482 @ 40), (N/A, 30)
++	(5735 - 5835 @ 40), (N/A, 30)
++
++country BR:
++	(2402 - 2482 @ 40), (N/A, 20)
++	(5170 - 5250 @ 40), (3, 17)
++	(5250 - 5330 @ 40), (3, 20), DFS
++	(5490 - 5710 @ 40), (3, 20), DFS
++	(5735 - 5835 @ 40), (3, 30)
++
++country BY:
++	(2402 - 2482 @ 40), (N/A, 20)
++	(5170 - 5250 @ 40), (N/A, 20)
++	(5250 - 5330 @ 40), (N/A, 20), DFS
++	(5490 - 5710 @ 40), (N/A, 27), DFS
++
++country BZ:
++	(2402 - 2482 @ 40), (N/A, 30)
++	(5735 - 5835 @ 40), (N/A, 30)
++
++country CA:
++	(2402 - 2472 @ 40), (3, 27)
++	(5170 - 5250 @ 40), (3, 17)
++	(5250 - 5330 @ 40), (3, 20), DFS
++	(5490 - 5710 @ 40), (3, 20), DFS
++	(5735 - 5835 @ 40), (3, 30)
++
++country CH: DFS-ETSI
++	(2402 - 2482 @ 40), (N/A, 20)
++	(5170 - 5250 @ 40), (N/A, 20)
++	(5250 - 5330 @ 40), (N/A, 20), DFS
++	(5490 - 5710 @ 40), (N/A, 27), DFS
++        # 60 gHz band channels 1-4, ref: Etsi En 302 567
++        (57240 - 65880 @ 2160), (N/A, 40), NO-OUTDOOR
++
++country CL:
++	(2402 - 2482 @ 40), (N/A, 20)
++	(5170 - 5250 @ 40), (N/A, 20)
++	(5250 - 5330 @ 40), (N/A, 20), DFS
++	(5735 - 5835 @ 40), (N/A, 20)
++
++country CN:
++	(2402 - 2482 @ 40), (N/A, 20)
++	(5735 - 5835 @ 40), (N/A, 30)
++	# 60 gHz band channels 1,4: 28dBm, channels 2,3: 44dBm
++	# ref: http://www.miit.gov.cn/n11293472/n11505629/n11506593/n11960250/n11960606/n11960700/n12330791.files/n12330790.pdf
++	(57240 - 59400 @ 2160), (N/A, 28)
++	(59400 - 63720 @ 2160), (N/A, 44)
++	(63720 - 65880 @ 2160), (N/A, 28)
++
++country CO:
++	(2402 - 2472 @ 40), (3, 27)
++	(5170 - 5250 @ 40), (3, 17)
++	(5250 - 5330 @ 40), (3, 23), DFS
++	(5735 - 5835 @ 40), (3, 30)
++
++country CR:
++	(2402 - 2482 @ 40), (N/A, 20)
++	(5170 - 5250 @ 20), (3, 17)
++	(5250 - 5330 @ 20), (3, 23), DFS
++	(5735 - 5835 @ 20), (3, 30)
++
++country CS:
++	(2402 - 2482 @ 40), (N/A, 20)
++	(5170 - 5250 @ 40), (N/A, 20)
++	(5250 - 5330 @ 40), (N/A, 20), DFS
++	(5490 - 5710 @ 40), (N/A, 27), DFS
++
++country CY: DFS-ETSI
++	(2402 - 2482 @ 40), (N/A, 20)
++	(5170 - 5250 @ 40), (N/A, 20)
++	(5250 - 5330 @ 40), (N/A, 20), DFS
++	(5490 - 5710 @ 40), (N/A, 27), DFS
++        # 60 gHz band channels 1-4, ref: Etsi En 302 567
++        (57240 - 65880 @ 2160), (N/A, 40), NO-OUTDOOR
++
++# Data from http://www.ctu.eu/164/download/VOR/VOR-12-08-2005-34.pdf
++# and http://www.ctu.eu/164/download/VOR/VOR-12-05-2007-6-AN.pdf
++# Power at 5250 - 5350 MHz and 5470 - 5725 MHz can be doubled if TPC is
++# implemented.
++country CZ: DFS-ETSI
++	(2400 - 2483.5 @ 40), (N/A, 100 mW)
++	(5150 - 5250 @ 40), (N/A, 200 mW), NO-OUTDOOR
++	(5250 - 5350 @ 40), (N/A, 100 mW), NO-OUTDOOR, DFS
++	(5470 - 5725 @ 40), (N/A, 500 mW), DFS
++        # 60 gHz band channels 1-4, ref: Etsi En 302 567
++        (57240 - 65880 @ 2160), (N/A, 40), NO-OUTDOOR
++
++# Data from "Frequenznutzungsplan" (as published in April 2008), downloaded from
++# http://www.bundesnetzagentur.de/cae/servlet/contentblob/38448/publicationFile/2659/Frequenznutzungsplan2008_Id17448pdf.pdf
++# For the 5GHz range also see
++# http://www.bundesnetzagentur.de/cae/servlet/contentblob/38216/publicationFile/6579/WLAN5GHzVfg7_2010_28042010pdf.pdf
++# The values have been reduced by a factor of 2 (3db) for non TPC devices
++# (in other words: devices with TPC can use twice the tx power of this table).
++# Note that the docs do not require TPC for 5150--5250; the reduction to
++# 100mW thus is not strictly required -- however the conservative 100mW
++# limit is used here as the non-interference with radar and satellite
++# apps relies on the attenuation by the building walls only in the
++# absence of DFS; the neighbour countries have 100mW limit here as well.
++
++country DE: DFS-ETSI
++	# entries 279004 and 280006
++	(2400 - 2483.5 @ 40), (N/A, 100 mW)
++	# entry 303005
++	(5150 - 5250 @ 40), (N/A, 100 mW), NO-OUTDOOR
++	# entries 304002 and 305002
++	(5250 - 5350 @ 40), (N/A, 100 mW), NO-OUTDOOR, DFS
++	# entries 308002, 309001 and 310003
++	(5470 - 5725 @ 40), (N/A, 500 mW), DFS
++        # 60 gHz band channels 1-4, ref: Etsi En 302 567
++        (57240 - 65880 @ 2160), (N/A, 40), NO-OUTDOOR
++
++country DK: DFS-ETSI
++	(2402 - 2482 @ 40), (N/A, 20)
++	(5170 - 5250 @ 40), (N/A, 20)
++	(5250 - 5330 @ 40), (N/A, 20), DFS
++	(5490 - 5710 @ 40), (N/A, 27), DFS
++        # 60 gHz band channels 1-4, ref: Etsi En 302 567
++        (57240 - 65880 @ 2160), (N/A, 40), NO-OUTDOOR
++
++country DO:
++	(2402 - 2472 @ 40), (3, 27)
++	(5170 - 5250 @ 40), (3, 17)
++	(5250 - 5330 @ 40), (3, 23), DFS
++	(5735 - 5835 @ 40), (3, 30)
++
++country DZ:
++	(2402 - 2482 @ 40), (N/A, 20)
++
++country EC:
++	(2402 - 2482 @ 40), (N/A, 20)
++	(5170 - 5250 @ 20), (3, 17)
++	(5250 - 5330 @ 20), (3, 23), DFS
++	(5735 - 5835 @ 20), (3, 30)
++
++country EE: DFS-ETSI
++	(2402 - 2482 @ 40), (N/A, 20)
++	(5170 - 5250 @ 40), (N/A, 20)
++	(5250 - 5330 @ 40), (N/A, 20), DFS
++	(5490 - 5710 @ 40), (N/A, 27), DFS
++        # 60 gHz band channels 1-4, ref: Etsi En 302 567
++        (57240 - 65880 @ 2160), (N/A, 40), NO-OUTDOOR
++
++country EG:
++	(2402 - 2482 @ 40), (N/A, 20)
++	(5170 - 5250 @ 20), (N/A, 20)
++	(5250 - 5330 @ 20), (N/A, 20), DFS
++
++country ES: DFS-ETSI
++	(2400 - 2483.5 @ 40), (N/A, 100 mW)
++	(5150 - 5250 @ 40), (N/A, 100 mW), NO-OUTDOOR
++	(5250 - 5350 @ 40), (N/A, 100 mW), NO-OUTDOOR, DFS
++	(5470 - 5725 @ 40), (N/A, 500 mW), DFS
++        # 60 gHz band channels 1-4, ref: Etsi En 302 567
++        (57240 - 65880 @ 2160), (N/A, 40), NO-OUTDOOR
++
++country FI: DFS-ETSI
++	(2402 - 2482 @ 40), (N/A, 20)
++	(5170 - 5250 @ 40), (N/A, 20)
++	(5250 - 5330 @ 40), (N/A, 20), DFS
++	(5490 - 5710 @ 40), (N/A, 27), DFS
++        # 60 gHz band channels 1-4, ref: Etsi En 302 567
++        (57240 - 65880 @ 2160), (N/A, 40), NO-OUTDOOR
++
++country FR: DFS-ETSI
++	(2402 - 2482 @ 40), (N/A, 20)
++	(5170 - 5250 @ 40), (N/A, 20)
++	(5250 - 5330 @ 40), (N/A, 20), DFS
++	(5490 - 5710 @ 40), (N/A, 27), DFS
++        # 60 gHz band channels 1-4, ref: Etsi En 302 567
++        (57240 - 65880 @ 2160), (N/A, 40), NO-OUTDOOR
++
++country GE:
++	(2402 - 2482 @ 40), (N/A, 20)
++	(5170 - 5250 @ 40), (N/A, 18)
++	(5250 - 5330 @ 40), (N/A, 18), DFS
++        # 60 gHz band channels 1-4, ref: Etsi En 302 567
++        (57240 - 65880 @ 2160), (N/A, 40), NO-OUTDOOR
++
++country GB: DFS-ETSI
++	(2402 - 2482 @ 40), (N/A, 20)
++	(5170 - 5250 @ 40), (N/A, 20)
++	(5250 - 5330 @ 40), (N/A, 20), DFS
++	(5490 - 5710 @ 40), (N/A, 27), DFS
++        # 60 gHz band channels 1-4, ref: Etsi En 302 567
++        (57240 - 65880 @ 2160), (N/A, 40), NO-OUTDOOR
++
++country GD:
++	(2402 - 2472 @ 40), (3, 27)
++	(5170 - 5250 @ 40), (3, 17)
++	(5250 - 5330 @ 40), (3, 20), DFS
++	(5490 - 5710 @ 40), (3, 20), DFS
++	(5735 - 5835 @ 40), (3, 30)
++
++country GR: DFS-ETSI
++	(2402 - 2482 @ 40), (N/A, 20)
++	(5170 - 5250 @ 40), (N/A, 20)
++	(5250 - 5330 @ 40), (N/A, 20), DFS
++	(5490 - 5710 @ 40), (N/A, 27), DFS
++        # 60 gHz band channels 1-4, ref: Etsi En 302 567
++        (57240 - 65880 @ 2160), (N/A, 40), NO-OUTDOOR
++
++country GL: DFS-ETSI
++	(2402 - 2482 @ 40), (N/A, 20)
++	(5170 - 5250 @ 20), (N/A, 20)
++	(5250 - 5330 @ 20), (N/A, 20), DFS
++	(5490 - 5710 @ 20), (N/A, 27), DFS
++
++country GT:
++	(2402 - 2472 @ 40), (3, 27)
++	(5170 - 5250 @ 40), (3, 17)
++	(5250 - 5330 @ 40), (3, 23), DFS
++	(5735 - 5835 @ 40), (3, 30)
++
++country GU:
++	(2402 - 2472 @ 40), (3, 27)
++	(5170 - 5250 @ 20), (3, 17)
++	(5250 - 5330 @ 20), (3, 23), DFS
++	(5735 - 5835 @ 20), (3, 30)
++
++country HN:
++	(2402 - 2482 @ 40), (N/A, 20)
++	(5170 - 5250 @ 40), (3, 17)
++	(5250 - 5330 @ 40), (3, 20), DFS
++	(5490 - 5710 @ 40), (3, 20), DFS
++	(5735 - 5835 @ 40), (3, 30)
++
++country HK:
++	(2402 - 2482 @ 40), (N/A, 20)
++	(5170 - 5250 @ 40), (3, 17)
++	(5250 - 5330 @ 40), (3, 20), DFS
++	(5490 - 5710 @ 40), (3, 20), DFS
++	(5735 - 5835 @ 40), (3, 30)
++
++country HR: DFS-ETSI
++	(2402 - 2482 @ 40), (N/A, 20)
++	(5170 - 5250 @ 40), (N/A, 20)
++	(5250 - 5330 @ 40), (N/A, 20), DFS
++	(5490 - 5710 @ 40), (N/A, 27), DFS
++        # 60 gHz band channels 1-4, ref: Etsi En 302 567
++        (57240 - 65880 @ 2160), (N/A, 40), NO-OUTDOOR
++
++country HT:
++	(2402 - 2482 @ 40), (N/A, 20)
++	(5170 - 5250 @ 40), (N/A, 20)
++	(5250 - 5330 @ 40), (N/A, 20), DFS
++	(5490 - 5710 @ 40), (N/A, 27), DFS
++
++country HU: DFS-ETSI
++	(2402 - 2482 @ 40), (N/A, 20)
++	(5170 - 5250 @ 40), (N/A, 20)
++	(5250 - 5330 @ 40), (N/A, 20), DFS
++	(5490 - 5710 @ 40), (N/A, 27), DFS
++        # 60 gHz band channels 1-4, ref: Etsi En 302 567
++        (57240 - 65880 @ 2160), (N/A, 40), NO-OUTDOOR
++
++country ID:
++	(2402 - 2482 @ 40), (N/A, 20)
++
++country IE: DFS-ETSI
++	(2402 - 2482 @ 40), (N/A, 20)
++	(5170 - 5250 @ 40), (N/A, 20)
++	(5250 - 5330 @ 40), (N/A, 20), DFS
++	(5490 - 5710 @ 40), (N/A, 27), DFS
++        # 60 gHz band channels 1-4, ref: Etsi En 302 567
++        (57240 - 65880 @ 2160), (N/A, 40), NO-OUTDOOR
++
++country IL:
++	(2402 - 2482 @ 40), (N/A, 20)
++	(5150 - 5250 @ 40), (N/A, 200 mW), NO-OUTDOOR
++	(5250 - 5350 @ 40), (N/A, 200 mW), NO-OUTDOOR, DFS
++
++country IN:
++	(2402 - 2482 @ 40), (N/A, 20)
++	(5170 - 5250 @ 40), (N/A, 20)
++	(5250 - 5330 @ 40), (N/A, 20), DFS
++	(5735 - 5835 @ 40), (N/A, 20)
++
++country IS: DFS-ETSI
++	(2402 - 2482 @ 40), (N/A, 20)
++	(5170 - 5250 @ 40), (N/A, 20)
++	(5250 - 5330 @ 40), (N/A, 20), DFS
++	(5490 - 5710 @ 40), (N/A, 27), DFS
++        # 60 gHz band channels 1-4, ref: Etsi En 302 567
++        (57240 - 65880 @ 2160), (N/A, 40), NO-OUTDOOR
++
++country IR:
++	(2402 - 2482 @ 40), (N/A, 20)
++	(5735 - 5835 @ 40), (N/A, 30)
++
++country IT: DFS-ETSI
++	(2402 - 2482 @ 40), (N/A, 20)
++	(5170 - 5250 @ 40), (N/A, 20)
++	(5250 - 5330 @ 40), (N/A, 20), DFS
++	(5490 - 5710 @ 40), (N/A, 27), DFS
++        # 60 gHz band channels 1-4, ref: Etsi En 302 567
++        (57240 - 65880 @ 2160), (N/A, 40), NO-OUTDOOR
++
++country JM:
++	(2402 - 2482 @ 40), (N/A, 20)
++	(5170 - 5250 @ 40), (3, 17)
++	(5250 - 5330 @ 40), (3, 20), DFS
++	(5490 - 5710 @ 40), (3, 20), DFS
++	(5735 - 5835 @ 40), (3, 30)
++
++country JP:
++	(2402 - 2482 @ 40), (N/A, 20)
++	(2474 - 2494 @ 20), (N/A, 20), NO-OFDM
++	(4910 - 4990 @ 40), (N/A, 23)
++	(5030 - 5090 @ 40), (N/A, 23)
++	(5170 - 5250 @ 40), (N/A, 20)
++	(5250 - 5330 @ 40), (N/A, 20), DFS
++	(5490 - 5710 @ 40), (N/A, 23), DFS
++
++country JO:
++	(2402 - 2482 @ 40), (N/A, 20)
++	(5170 - 5250 @ 40), (N/A, 18)
++
++country KE:
++	(2402 - 2482 @ 40), (N/A, 20)
++	(5735 - 5835 @ 40), (N/A, 30)
++
++country KH:
++	(2402 - 2482 @ 40), (N/A, 20)
++	(5170 - 5250 @ 40), (N/A, 20)
++	(5250 - 5330 @ 40), (N/A, 20), DFS
++	(5490 - 5710 @ 40), (N/A, 27), DFS
++
++country KP:
++	(2402 - 2482 @ 40), (N/A, 20)
++	(5170 - 5330 @ 40), (3, 20)
++	(5160 - 5250 @ 40), (3, 20), DFS
++	(5490 - 5630 @ 40), (3, 30), DFS
++	(5735 - 5815 @ 40), (3, 30)
++
++country KR:
++	(2402 - 2482 @ 20), (N/A, 20)
++	(5170 - 5250 @ 20), (3, 20)
++	(5250 - 5330 @ 20), (3, 20), DFS
++	(5490 - 5630 @ 20), (3, 30), DFS
++	(5735 - 5815 @ 20), (3, 30)
++
++country KW:
++	(2402 - 2482 @ 40), (N/A, 20)
++	(5170 - 5250 @ 40), (N/A, 20)
++	(5250 - 5330 @ 40), (N/A, 20), DFS
++
++country KZ:
++	(2402 - 2482 @ 40), (N/A, 20)
++
++country LB:
++	(2402 - 2482 @ 40), (N/A, 20)
++	(5735 - 5835 @ 40), (N/A, 30)
++
++country LI: DFS-ETSI
++	(2402 - 2482 @ 40), (N/A, 20)
++	(5170 - 5250 @ 40), (N/A, 20)
++	(5250 - 5330 @ 40), (N/A, 20), DFS
++	(5490 - 5710 @ 40), (N/A, 27), DFS
++
++country LK:
++	(2402 - 2482 @ 40), (N/A, 20)
++	(5170 - 5250 @ 20), (3, 17)
++	(5250 - 5330 @ 20), (3, 20), DFS
++	(5490 - 5710 @ 20), (3, 20), DFS
++	(5735 - 5835 @ 20), (3, 30)
++
++country LT: DFS-ETSI
++	(2402 - 2482 @ 40), (N/A, 20)
++	(5170 - 5250 @ 40), (N/A, 20)
++	(5250 - 5330 @ 40), (N/A, 20), DFS
++	(5490 - 5710 @ 40), (N/A, 27), DFS
++        # 60 gHz band channels 1-4, ref: Etsi En 302 567
++        (57240 - 65880 @ 2160), (N/A, 40), NO-OUTDOOR
++
++country LU: DFS-ETSI
++	(2402 - 2482 @ 40), (N/A, 20)
++	(5170 - 5250 @ 40), (N/A, 20)
++	(5250 - 5330 @ 40), (N/A, 20), DFS
++	(5490 - 5710 @ 40), (N/A, 27), DFS
++        # 60 gHz band channels 1-4, ref: Etsi En 302 567
++        (57240 - 65880 @ 2160), (N/A, 40), NO-OUTDOOR
++
++country LV: DFS-ETSI
++	(2402 - 2482 @ 40), (N/A, 20)
++	(5170 - 5250 @ 40), (N/A, 20)
++	(5250 - 5330 @ 40), (N/A, 20), DFS
++	(5490 - 5710 @ 40), (N/A, 27), DFS
++        # 60 gHz band channels 1-4, ref: Etsi En 302 567
++        (57240 - 65880 @ 2160), (N/A, 40), NO-OUTDOOR
++
++country MC: DFS-ETSI
++	(2402 - 2482 @ 40), (N/A, 20)
++	(5170 - 5250 @ 40), (N/A, 18)
++	(5250 - 5330 @ 40), (N/A, 18), DFS
++
++country MA:
++	(2402 - 2482 @ 40), (N/A, 20)
++
++country MO:
++	(2402 - 2482 @ 40), (N/A, 20)
++	(5170 - 5250 @ 40), (3, 23)
++	(5250 - 5330 @ 40), (3, 23), DFS
++	(5735 - 5835 @ 40), (3, 30)
++
++country MK: DFS-ETSI
++	(2402 - 2482 @ 40), (N/A, 20)
++	(5170 - 5250 @ 40), (N/A, 20)
++	(5250 - 5330 @ 40), (N/A, 20), DFS
++	(5490 - 5710 @ 40), (N/A, 27), DFS
++        # 60 gHz band channels 1-4, ref: Etsi En 302 567
++        (57240 - 65880 @ 2160), (N/A, 40), NO-OUTDOOR
++
++country MT: DFS-ETSI
++	(2402 - 2482 @ 40), (N/A, 20)
++	(5170 - 5250 @ 40), (N/A, 20)
++	(5250 - 5330 @ 40), (N/A, 20), DFS
++	(5490 - 5710 @ 40), (N/A, 27), DFS
++        # 60 gHz band channels 1-4, ref: Etsi En 302 567
++        (57240 - 65880 @ 2160), (N/A, 40), NO-OUTDOOR
++
++country MY:
++	(2402 - 2482 @ 40), (N/A, 20)
++	(5250 - 5330 @ 40), (N/A, 30), DFS
++	(5735 - 5835 @ 40), (N/A, 30)
++
++country MX:
++	(2402 - 2472 @ 40), (3, 27)
++	(5170 - 5250 @ 40), (3, 17)
++	(5250 - 5330 @ 40), (3, 23), DFS
++	(5735 - 5835 @ 40), (3, 30)
++
++country NL: DFS-ETSI
++	(2402 - 2482 @ 40), (N/A, 20)
++	(5170 - 5250 @ 40), (N/A, 20), NO-OUTDOOR
++	(5250 - 5330 @ 40), (N/A, 20), NO-OUTDOOR, DFS
++	(5490 - 5710 @ 40), (N/A, 27), DFS
++        # 60 gHz band channels 1-4, ref: Etsi En 302 567
++        (57240 - 65880 @ 2160), (N/A, 40), NO-OUTDOOR
++
++country NO: DFS-ETSI
++	(2402 - 2482 @ 40), (N/A, 20)
++	(5170 - 5250 @ 40), (N/A, 20)
++	(5250 - 5330 @ 40), (N/A, 20), DFS
++	(5490 - 5710 @ 40), (N/A, 27), DFS
++        # 60 gHz band channels 1-4, ref: Etsi En 302 567
++        (57240 - 65880 @ 2160), (N/A, 40), NO-OUTDOOR
++
++country NP:
++	(2402 - 2482 @ 40), (N/A, 20)
++	(5735 - 5835 @ 40), (N/A, 30)
++
++country NZ:
++	(2402 - 2482 @ 40), (N/A, 30)
++	(5170 - 5250 @ 20), (3, 23)
++	(5250 - 5330 @ 20), (3, 23), DFS
++	(5735 - 5835 @ 20), (3, 30)
++
++country OM:
++	(2402 - 2482 @ 40), (N/A, 20)
++	(5170 - 5250 @ 40), (3, 17)
++	(5250 - 5330 @ 40), (3, 20), DFS
++	(5490 - 5710 @ 40), (3, 20), DFS
++	(5735 - 5835 @ 40), (3, 30)
++
++country PA:
++	(2402 - 2472 @ 40), (3, 27)
++	(5170 - 5250 @ 40), (3, 17)
++	(5250 - 5330 @ 40), (3, 23), DFS
++	(5735 - 5835 @ 40), (3, 30)
++
++country PE:
++	(2402 - 2482 @ 40), (N/A, 20)
++	(5735 - 5835 @ 40), (N/A, 30)
++
++country PG:
++	(2402 - 2482 @ 40), (N/A, 20)
++	(5170 - 5250 @ 40), (3, 17)
++	(5250 - 5330 @ 40), (3, 23), DFS
++	(5735 - 5835 @ 40), (3, 30)
++
++country PH:
++	(2402 - 2482 @ 40), (N/A, 20)
++	(5735 - 5835 @ 40), (N/A, 30)
++
++country PK:
++	(2402 - 2482 @ 40), (N/A, 20)
++	(5735 - 5835 @ 40), (N/A, 30)
++
++country PL: DFS-ETSI
++	(2402 - 2482 @ 40), (N/A, 20)
++	(5170 - 5250 @ 40), (N/A, 20)
++	(5250 - 5330 @ 40), (N/A, 20), DFS
++	(5490 - 5710 @ 40), (N/A, 27), DFS
++        # 60 gHz band channels 1-4, ref: Etsi En 302 567
++        (57240 - 65880 @ 2160), (N/A, 40), NO-OUTDOOR
++
++country PT: DFS-ETSI
++	(2402 - 2482 @ 40), (N/A, 20)
++	(5170 - 5250 @ 40), (N/A, 20)
++	(5250 - 5330 @ 40), (N/A, 20), DFS
++	(5490 - 5710 @ 40), (N/A, 27), DFS
++        # 60 gHz band channels 1-4, ref: Etsi En 302 567
++        (57240 - 65880 @ 2160), (N/A, 40), NO-OUTDOOR
++
++country PR:
++	(2402 - 2472 @ 40), (3, 27)
++	(5170 - 5250 @ 40), (3, 17)
++	(5250 - 5330 @ 40), (3, 23), DFS
++	(5735 - 5835 @ 40), (3, 30)
++
++country QA:
++	(2402 - 2482 @ 40), (N/A, 20)
++	(5735 - 5835 @ 40), (N/A, 30)
++
++country RO: DFS-ETSI
++	(2402 - 2482 @ 40), (N/A, 20)
++	(5170 - 5250 @ 40), (N/A, 20)
++	(5250 - 5330 @ 40), (N/A, 20), DFS
++	(5490 - 5710 @ 40), (N/A, 27), DFS
++        # 60 gHz band channels 1-4, ref: Etsi En 302 567
++        (57240 - 65880 @ 2160), (N/A, 40), NO-OUTDOOR
++
++country RS:
++        # 60 gHz band channels 1-4, ref: Etsi En 302 567
++        (57240 - 65880 @ 2160), (N/A, 40), NO-OUTDOOR
++
++country RU:
++	(2402 - 2482 @ 40), (N/A, 20)
++	(5735 - 5835 @ 20), (N/A, 30)
++
++country RW:
++	(2402 - 2482 @ 40), (N/A, 20)
++	(5735 - 5835 @ 40), (N/A, 30)
++
++country SA:
++	(2402 - 2482 @ 40), (N/A, 20)
++	(5170 - 5250 @ 20), (3, 23)
++	(5250 - 5330 @ 20), (3, 23), DFS
++	(5735 - 5835 @ 20), (3, 30)
++
++country SE: DFS-ETSI
++	(2402 - 2482 @ 40), (N/A, 20)
++	(5170 - 5250 @ 40), (N/A, 20)
++	(5250 - 5330 @ 40), (N/A, 20), DFS
++	(5490 - 5710 @ 40), (N/A, 27), DFS
++        # 60 gHz band channels 1-4, ref: Etsi En 302 567
++        (57240 - 65880 @ 2160), (N/A, 40), NO-OUTDOOR
++
++country SG:
++	(2402 - 2482 @ 40), (N/A, 20)
++	(5170 - 5250 @ 40), (N/A, 20)
++	(5250 - 5330 @ 40), (N/A, 20), DFS
++	(5735 - 5835 @ 40), (N/A, 20)
++
++country SI: DFS-ETSI
++	(2402 - 2482 @ 40), (N/A, 20)
++	(5170 - 5250 @ 40), (N/A, 20)
++	(5250 - 5330 @ 40), (N/A, 20), DFS
++	(5490 - 5710 @ 40), (N/A, 27), DFS
++        # 60 gHz band channels 1-4, ref: Etsi En 302 567
++        (57240 - 65880 @ 2160), (N/A, 40), NO-OUTDOOR
++
++country SK: DFS-ETSI
++	(2402 - 2482 @ 40), (N/A, 20)
++	(5170 - 5250 @ 40), (N/A, 20)
++	(5250 - 5330 @ 40), (N/A, 20), DFS
++	(5490 - 5710 @ 40), (N/A, 27), DFS
++        # 60 gHz band channels 1-4, ref: Etsi En 302 567
++        (57240 - 65880 @ 2160), (N/A, 40), NO-OUTDOOR
++
++country SV:
++	(2402 - 2482 @ 40), (N/A, 20)
++	(5170 - 5250 @ 20), (3, 17)
++	(5250 - 5330 @ 20), (3, 23), DFS
++	(5735 - 5835 @ 20), (3, 30)
++
++country SY:
++	(2402 - 2482 @ 40), (N/A, 20)
++
++country TW:
++	(2402 - 2472 @ 40), (3, 27)
++	(5270 - 5330 @ 40), (3, 17), DFS
++	(5735 - 5815 @ 40), (3, 30)
++
++country TH:
++	(2402 - 2482 @ 40), (N/A, 20)
++	(5170 - 5250 @ 40), (3, 17)
++	(5250 - 5330 @ 40), (3, 20), DFS
++	(5490 - 5710 @ 40), (3, 20), DFS
++	(5735 - 5835 @ 40), (3, 30)
++
++country TT:
++	(2402 - 2482 @ 40), (N/A, 20)
++	(5170 - 5250 @ 40), (3, 17)
++	(5250 - 5330 @ 40), (3, 20), DFS
++	(5490 - 5710 @ 40), (3, 20), DFS
++	(5735 - 5835 @ 40), (3, 30)
++
++country TN:
++	(2402 - 2482 @ 40), (N/A, 20)
++	(5170 - 5250 @ 20), (N/A, 20)
++	(5250 - 5330 @ 20), (N/A, 20), DFS
++
++country TR: DFS-ETSI
++	(2402 - 2482 @ 40), (N/A, 20)
++	(5170 - 5250 @ 20), (N/A, 20)
++	(5250 - 5330 @ 20), (N/A, 20), DFS
++	# 60 gHz band channels 1-4, ref: Etsi En 302 567
++	(57240 - 65880 @ 2160), (N/A, 40), NO-OUTDOOR
++ 
++# Source:
++# #914 / 06 Sep 2007: http://www.ucrf.gov.ua/uk/doc/nkrz/1196068874
++# #1174 / 23 Oct 2008: http://www.nkrz.gov.ua/uk/activities/ruling/1225269361
++# (appendix 8)
++# Listed 5GHz range is a lowest common denominator for all related
++# rules in the referenced laws. Such a range is used because of
++# disputable definitions there.
++country UA:
++	(2400 - 2483.5 @ 40), (N/A, 20), NO-OUTDOOR
++	(5150 - 5350 @ 40), (N/A, 20), NO-OUTDOOR
++	# 60 gHz band channels 1-4, ref: Etsi En 302 567
++	(57240 - 65880 @ 2160), (N/A, 40), NO-OUTDOOR
++
++country US: DFS-FCC
++	(2402 - 2472 @ 40), (3, 27)
++	(5170 - 5250 @ 40), (3, 17)
++	(5250 - 5330 @ 40), (3, 20), DFS
++	(5490 - 5600 @ 40), (3, 20), DFS
++	(5650 - 5710 @ 40), (3, 20), DFS
++	(5735 - 5835 @ 40), (3, 30)
++	# 60g band
++	# reference: http://cfr.regstoday.com/47cfr15.aspx#47_CFR_15p255
++	# channels 1,2,3, EIRP=40dBm(43dBm peak)
++	(57240 - 63720 @ 2160), (N/A, 40)
++
++country UY:
++	(2402 - 2482 @ 40), (N/A, 20)
++	(5170 - 5250 @ 40), (3, 17)
++	(5250 - 5330 @ 40), (3, 20), DFS
++	(5490 - 5710 @ 40), (3, 20), DFS
++	(5735 - 5835 @ 40), (3, 30)
++
++country UZ:
++	(2402 - 2472 @ 40), (3, 27)
++	(5170 - 5250 @ 40), (3, 17)
++	(5250 - 5330 @ 40), (3, 20), DFS
++	(5490 - 5710 @ 40), (3, 20), DFS
++	(5735 - 5835 @ 40), (3, 30)
++
++country VE:
++	(2402 - 2482 @ 40), (N/A, 20)
++	(5735 - 5815 @ 40), (N/A, 23)
++
++country VN:
++	(2402 - 2482 @ 40), (N/A, 20)
++	(5170 - 5250 @ 40), (N/A, 20)
++	(5250 - 5330 @ 40), (N/A, 20), DFS
++
++country YE:
++	(2402 - 2482 @ 40), (N/A, 20)
++
++country ZA:
++	(2402 - 2482 @ 40), (N/A, 20)
++	(5170 - 5250 @ 40), (3, 17)
++	(5250 - 5330 @ 40), (3, 20), DFS
++	(5490 - 5710 @ 40), (3, 20), DFS
++	(5735 - 5835 @ 40), (3, 30)
++
++country ZW:
++	(2402 - 2482 @ 40), (N/A, 20)
++
diff --git a/linux-bsp/patches/u-boot-2010.09-fl2440.patch b/linux-bsp/patches/u-boot-2010.09-fl2440.patch
new file mode 100644
index 0000000..50de68b
--- /dev/null
+++ b/linux-bsp/patches/u-boot-2010.09-fl2440.patch
@@ -0,0 +1,2075 @@
+diff -Nuar u-boot-2010.09/arch/arm/cpu/arm920t/s3c24x0/speed.c u-boot-2010.09-fl2440/arch/arm/cpu/arm920t/s3c24x0/speed.c
+--- u-boot-2010.09/arch/arm/cpu/arm920t/s3c24x0/speed.c	2010-09-29 05:20:55.000000000 +0800
++++ u-boot-2010.09-fl2440/arch/arm/cpu/arm920t/s3c24x0/speed.c	2020-01-09 17:22:17.705412170 +0800
+@@ -64,6 +64,11 @@
+ 	p = ((r & 0x003F0) >> 4) + 2;
+ 	s = r & 0x3;
+ 
++#if defined(CONFIG_S3C2440) /* Add by guowenxue*/
++    if (pllreg == MPLL)
++        return ((CONFIG_SYS_CLK_FREQ * m * 2) /(p << s));
++    else if (pllreg == UPLL)
++#endif /* Add end*/
+ 	return (CONFIG_SYS_CLK_FREQ * m) / (p << s);
+ }
+ 
+@@ -78,7 +83,22 @@
+ {
+ 	struct s3c24x0_clock_power *clk_power = s3c24x0_get_base_clock_power();
+ 
++#if defined(CONFIG_S3C2440) 
++    if (readl(&clk_power->CLKDIVN) & 0x6)
++    {
++        if ((readl(&clk_power->CLKDIVN) & 0x6)==2)
++            return(get_FCLK()/2);
++        if ((readl(&clk_power->CLKDIVN) & 0x6)==6)
++            return((readl(&clk_power->CAMDIVN) & 0x100) ? get_FCLK()/6 : get_FCLK()/3);
++        if ((readl(&clk_power->CLKDIVN) & 0x6)==4)
++            return((readl(&clk_power->CAMDIVN) & 0x200) ? get_FCLK()/8 : get_FCLK()/4);
++        return(get_FCLK());
++    }
++    else
++        return(get_FCLK());
++#else
+ 	return (readl(&clk_power->CLKDIVN) & 2) ? get_FCLK() / 2 : get_FCLK();
++#endif
+ }
+ 
+ /* return PCLK frequency */
+@@ -95,4 +115,17 @@
+ 	return get_PLLCLK(UPLL);
+ }
+ 
++
++#if defined(CONFIG_DISPLAY_CPUINFO)
++int print_cpuinfo(void)
++{   
++    printf("S3C2440A CPU clock   : %lu MHz\n", get_FCLK());
++    printf("S3C2440A HSB clock   : %lu MHz\n", get_HCLK());
++    printf("S3C2440A PSB clock   : %lu MHz\n", get_PCLK());
++    printf("S3C2440A USB clock   : %lu MHz\n", get_FCLK());
++
++    return 0;
++}
++#endif
++
+ #endif /* CONFIG_S3C24X0 */
+diff -Nuar u-boot-2010.09/arch/arm/cpu/arm920t/s3c24x0/timer.c u-boot-2010.09-fl2440/arch/arm/cpu/arm920t/s3c24x0/timer.c
+--- u-boot-2010.09/arch/arm/cpu/arm920t/s3c24x0/timer.c	2010-09-29 05:20:55.000000000 +0800
++++ u-boot-2010.09-fl2440/arch/arm/cpu/arm920t/s3c24x0/timer.c	2020-01-09 17:22:17.705412170 +0800
+@@ -181,6 +181,7 @@
+ 	tbclk = timer_load_val * 100;
+ #elif defined(CONFIG_SBC2410X) || \
+       defined(CONFIG_SMDK2410) || \
++      defined(CONFIG_FL2440) || \
+       defined(CONFIG_VCMA9)
+ 	tbclk = CONFIG_SYS_HZ;
+ #else
+diff -Nuar u-boot-2010.09/arch/arm/cpu/arm920t/start.S u-boot-2010.09-fl2440/arch/arm/cpu/arm920t/start.S
+--- u-boot-2010.09/arch/arm/cpu/arm920t/start.S	2010-09-29 05:20:55.000000000 +0800
++++ u-boot-2010.09-fl2440/arch/arm/cpu/arm920t/start.S	2020-01-09 17:22:17.705412170 +0800
+@@ -114,8 +114,8 @@
+ 	orr	r0, r0, #0xd3
+ 	msr	cpsr, r0
+ 
+-	bl	coloured_LED_init
+-	bl	red_LED_on
++	@bl	coloured_LED_init
++	@bl	red_LED_on
+ 
+ #if	defined(CONFIG_AT91RM9200DK) || defined(CONFIG_AT91RM9200EK)
+ 	/*
+@@ -159,13 +159,63 @@
+ 	ldr	r1, =0x3ff
+ 	ldr	r0, =INTSUBMSK
+ 	str	r1, [r0]
++#elif defined CONFIG_S3C2440
++    ldr     r1, =0x7fff
++    ldr     r0, =INTSUBMSK 
++    str     r1, [r0]
+ # endif
+ 
++# if defined(CONFIG_S3C2440)
++#define GPBCON                      0x56000010
++#define GPBDAT                      0x56000014
++#define GPBUP                       0x56000018
++    /*Set GPIO5, GPIO6, GPIO8, GPIO10 as GPIO OUTPUT mode*/
++    ldr r0, =GPBCON
++    ldr r1, [r0]
++    bic r1, r1, #0x3c00      /*Set GPBCON for GPIO5,GPIO6 as 0x00 */
++    orr r1, r1, #0x1400      /*Set GPBCON for GPIO5,GPIO6 as GPIOOUT, 0x01*/
++    bic r1, r1, #0x00330000  /*Set GPBCON for GPIO8,GPIO10 as 0x00*/
++    orr r1, r1, #0x00110000  /*Set GPBCON for GPIO8,GPIO10 as GPIOOUT, 0x01*/
++    str r1, [r0]
++
++    /*Set internal pullup resister*/ 
++    ldr r0, =GPBUP 
++    ldr r1, [r0] 
++    orr r1, r1, #0x0560     /*Set bit 5,6,8,10, disable pullup resister*/ 
++    str r1, [r0]
++
++    ldr     r2, =GPBDAT
++    ldr     r3, [r2]
++    orr     r3, r3, #0x0560     /*Set bit 5,6,8,10 as high level, Turn Off LED*/
++    str     r3, [r2]
++
++#  define MPLLCON        0x4C000004 
++#  define MDIV_405        0x7f << 12  
++#  define PSDIV_405       0x21         
++
++
++    /* FCLK:HCLK:PCLK = 1:4:8 */
++    ldr r0, =CLKDIVN
++    mov r1, #0x05
++    str r1, [r0]
++
++    mrc p15, 0, r1, c1, c0, 0
++    orr r1, r1, #0xc0000000
++    mcr p15, 0, r1, c1, c0, 0 
++
++    Ldr r0,=MPLLCON
++    mov r1, #MDIV_405
++    add r1, r1, #PSDIV_405
++    str r1, [r0]
++
++
++#else /*S3C2410, S3C2440 */
+ 	/* FCLK:HCLK:PCLK = 1:2:4 */
+ 	/* default FCLK is 120 MHz ! */
+ 	ldr	r0, =CLKDIVN
+ 	mov	r1, #3
+ 	str	r1, [r0]
++#endif /* end of if defined(CONFIG_S3C2440) */
+ #endif	/* CONFIG_S3C24X0 */
+ 
+ 	/*
+@@ -183,6 +233,92 @@
+ 	cmp	r0, r1			/* don't reloc during debug         */
+ 	beq	stack_setup
+ 
++judgment_norflash_nandflash_boot:
++    ldr r1, =( (4<<28)|(3<<4)|(3<<2) ) 
++    mov r0, #0
++    str r0, [r1]
++
++    mov r1, #0x3c
++    ldr r0, [r1]
++    cmp r0, #0
++    bne norflash_boot
++
++    /*Nandflash boot going here, recovery address 0x0000003C date*/
++    ldr r0, =(0xdeadbeef)
++    ldr r1, =( (4<<28)|(3<<4)|(3<<2) )
++    str r0, [r1]
++
++nandflash_boot:
++#define LENGTH_UBOOT 0x60000 
++#define NAND_CTL_BASE 0x4E000000
++/* Offset */
++#define oNFCONF 0x00
++#define oNFCONT 0x04
++#define oNFCMD 0x08
++#define oNFSTAT 0x20
++
++    mov r1, #NAND_CTL_BASE 
++    ldr r2, =( (7<<12)|(7<<8)|(7<<4)|(0<<0) )
++    str r2, [r1, #oNFCONF]
++    ldr r2, [r1, #oNFCONF]
++
++    ldr r2, =( (1<<4)|(0<<1)|(1<<0) )   @ Active low CE Control
++    str r2, [r1, #oNFCONT]
++    ldr r2, [r1, #oNFCONT]
++
++    ldr r2, =(0x6)  @ RnB Clear 
++    str r2, [r1, #oNFSTAT] 
++    ldr r2, [r1, #oNFSTAT]
++
++    mov r2, #0xff   @ RESET command 
++    strb    r2, [r1, #oNFCMD]
++
++    mov r3, #0  @ wait
++nand_delay:
++    add r3, r3, #0x1 
++    cmp r3, #0xa 
++    blt nand_delay
++
++nand_wait:
++    ldr r2, [r1, #oNFSTAT]  @ wait ready 
++    tst r2, #0x4 
++    beq nand_wait
++
++    ldr r2, [r1, #oNFCONT] 
++    orr r2, r2, #0x2    @ Flash Memory Chip Disable 
++    str r2, [r1, #oNFCONT]
++
++    ldr sp, DW_STACK_START  @ setup stack pointer
++    mov fp, #0  @ no previous frame, so fp=0
++
++    ldr r0, =TEXT_BASE 
++    mov r1, #0x0 
++    mov r2, #LENGTH_UBOOT 
++    bl  nand_read_ll 
++    tst r0, #0x0 
++    bne infinite_loop     /*nand_read_ll() not return 0, then goto dead loop*/
++
++nand_read_ok:
++    /*Then verify the read data validation*/
++    mov r0, #0 
++    ldr r1, =TEXT_BASE 
++    mov r2, #0x400  @ 4 bytes * 1024 = 4K-bytes 
++    
++compare_next_byte:
++    ldr r3, [r0], #4 
++    ldr r4, [r1], #4
++    teq r3, r4 
++    bne infinite_loop
++    
++    subs    r2, r2, #4 
++    beq stack_setup 
++    bne compare_next_byte
++                                            
++infinite_loop: 
++    b   infinite_loop   @ infinite loop
++
++norflash_boot:
++
+ 	ldr	r2, _armboot_start
+ 	ldr	r3, _bss_start
+ 	sub	r2, r3, r2		/* r2 <- size of armboot            */
+@@ -216,10 +352,22 @@
+ 	cmp	r0, r1
+ 	ble	clbss_l
+ 
++    ldr r1, =GPBDAT
++    ldr r2, [r1]
++    bic r2, r2, #(1<<5)  
++    str r2, [r1]
++ 
+ 	ldr	pc, _start_armboot
+ 
+ _start_armboot:	.word start_armboot
+ 
++#ifdef CONFIG_S3C24X0
++#define STACK_BASE 0x33f00000
++#define STACK_SIZE 0x10000
++    .align  2
++    DW_STACK_START: .word   STACK_BASE+STACK_SIZE-4
++#endif
++
+ 
+ /*
+  *************************************************************************
+diff -Nuar u-boot-2010.09/arch/arm/cpu/arm920t/u-boot.lds u-boot-2010.09-fl2440/arch/arm/cpu/arm920t/u-boot.lds
+--- u-boot-2010.09/arch/arm/cpu/arm920t/u-boot.lds	2010-09-29 05:20:55.000000000 +0800
++++ u-boot-2010.09-fl2440/arch/arm/cpu/arm920t/u-boot.lds	2020-01-09 17:22:17.705412170 +0800
+@@ -40,6 +40,8 @@
+ 	.text :
+ 	{
+ 		arch/arm/cpu/arm920t/start.o	(.text)
++        board/lingyun/fl2440/lowlevel_init.o    (.text)
++        board/lingyun/fl2440/nand_read.o    (.text)
+ 		*(.text)
+ 	}
+ 
+diff -Nuar u-boot-2010.09/arch/arm/include/asm/arch-s3c24x0/s3c24x0_cpu.h u-boot-2010.09-fl2440/arch/arm/include/asm/arch-s3c24x0/s3c24x0_cpu.h
+--- u-boot-2010.09/arch/arm/include/asm/arch-s3c24x0/s3c24x0_cpu.h	2010-09-29 05:20:55.000000000 +0800
++++ u-boot-2010.09-fl2440/arch/arm/include/asm/arch-s3c24x0/s3c24x0_cpu.h	2020-01-09 17:22:17.705412170 +0800
+@@ -20,7 +20,7 @@
+ 
+ #ifdef CONFIG_S3C2400
+ 	#include <asm/arch/s3c2400.h>
+-#elif defined CONFIG_S3C2410
++#elif defined(CONFIG_S3C2410) || defined(CONFIG_S3C2440)
+ 	#include <asm/arch/s3c2410.h>
+ #else
+ 	#error Please define the s3c24x0 cpu type
+diff -Nuar u-boot-2010.09/arch/arm/include/asm/arch-s3c24x0/s3c24x0.h u-boot-2010.09-fl2440/arch/arm/include/asm/arch-s3c24x0/s3c24x0.h
+--- u-boot-2010.09/arch/arm/include/asm/arch-s3c24x0/s3c24x0.h	2010-09-29 05:20:55.000000000 +0800
++++ u-boot-2010.09-fl2440/arch/arm/include/asm/arch-s3c24x0/s3c24x0.h	2020-01-09 17:22:17.705412170 +0800
+@@ -78,7 +78,7 @@
+ 	u32	PRIORITY;
+ 	u32	INTPND;
+ 	u32	INTOFFSET;
+-#ifdef CONFIG_S3C2410
++#if defined(CONFIG_S3C2410) || defined (CONFIG_S3C2440)
+ 	u32	SUBSRCPND;
+ 	u32	INTSUBMSK;
+ #endif
+@@ -88,11 +88,11 @@
+ /* DMAS (see manual chapter 8) */
+ struct s3c24x0_dma {
+ 	u32	DISRC;
+-#ifdef CONFIG_S3C2410
++#if defined(CONFIG_S3C2410) || defined (CONFIG_S3C2440)
+ 	u32	DISRCC;
+ #endif
+ 	u32	DIDST;
+-#ifdef CONFIG_S3C2410
++#if defined(CONFIG_S3C2410) || defined (CONFIG_S3C2440)
+ 	u32	DIDSTC;
+ #endif
+ 	u32	DCON;
+@@ -103,7 +103,7 @@
+ #ifdef CONFIG_S3C2400
+ 	u32	res[1];
+ #endif
+-#ifdef CONFIG_S3C2410
++#if defined(CONFIG_S3C2410) || defined (CONFIG_S3C2440)
+ 	u32	res[7];
+ #endif
+ };
+@@ -122,6 +122,9 @@
+ 	u32	CLKCON;
+ 	u32	CLKSLOW;
+ 	u32	CLKDIVN;
++#if defined (CONFIG_S3C2440) 
++    u32 CAMDIVN;
++#endif
+ };
+ 
+ 
+@@ -141,7 +144,7 @@
+ 	u32	res[8];
+ 	u32	DITHMODE;
+ 	u32	TPAL;
+-#ifdef CONFIG_S3C2410
++#if defined(CONFIG_S3C2410) || defined (CONFIG_S3C2440)
+ 	u32	LCDINTPND;
+ 	u32	LCDSRCPND;
+ 	u32	LCDINTMSK;
+@@ -151,6 +154,7 @@
+ 
+ 
+ /* NAND FLASH (see S3C2410 manual chapter 6) */
++#if defined(CONFIG_S3C2410)
+ struct s3c2410_nand {
+ 	u32	NFCONF;
+ 	u32	NFCMD;
+@@ -159,6 +163,26 @@
+ 	u32	NFSTAT;
+ 	u32	NFECC;
+ };
++#elif defined (CONFIG_S3C2440)
++struct s3c2410_nand { 
++    u32 NFCONF; 
++    u32 NFCONT; 
++    u32 NFCMD; 
++    u32 NFADDR; 
++    u32 NFDATA; 
++    u32 NFMECCD0; 
++    u32 NFMECCD1; 
++    u32 NFSECCD; 
++    u32 NFSTAT; 
++    u32 NFESTAT0; 
++    u32 NFESTAT1; 
++    u32 NFMECC0; 
++    u32 NFMECC1; 
++    u32 NFSECC; 
++    u32 NFSBLK; 
++    u32 NFEBLK;
++};
++#endif
+ 
+ 
+ /* UART (see manual chapter 11) */
+@@ -397,7 +421,7 @@
+ 	u32	MISCCR;
+ 	u32	EXTINT;
+ #endif
+-#ifdef CONFIG_S3C2410
++#if defined(CONFIG_S3C2410) || defined (CONFIG_S3C2440)
+ 	u32	GPACON;
+ 	u32	GPADAT;
+ 	u32	res1[2];
+@@ -446,6 +470,13 @@
+ 	u32	GSTATUS2;
+ 	u32	GSTATUS3;
+ 	u32	GSTATUS4;
++#if defined (CONFIG_S3C2440) 
++    u32 res9[3]; 
++    u32 MSLCON; 
++    u32 GPJCON; 
++    u32 GPJDAT; 
++    u32 GPJUP;
++#endif
+ #endif
+ };
+ 
+diff -Nuar u-boot-2010.09/board/lingyun/fl2440/config.mk u-boot-2010.09-fl2440/board/lingyun/fl2440/config.mk
+--- u-boot-2010.09/board/lingyun/fl2440/config.mk	1970-01-01 08:00:00.000000000 +0800
++++ u-boot-2010.09-fl2440/board/lingyun/fl2440/config.mk	2020-01-09 17:22:17.705412170 +0800
+@@ -0,0 +1,25 @@
++#
++# (C) Copyright 2002
++# Gary Jennejohn, DENX Software Engineering, <garyj@denx.de>
++# David Mueller, ELSOFT AG, <d.mueller@elsoft.ch>
++#
++# SAMSUNG SMDK2410 board with S3C2410X (ARM920T) cpu
++#
++# see http://www.samsung.com/ for more information on SAMSUNG
++#
++
++#
++# SMDK2410 has 1 bank of 64 MB DRAM
++#
++# 3000'0000 to 3400'0000
++#
++# Linux-Kernel is expected to be at 3000'8000, entry 3000'8000
++# optionally with a ramdisk at 3080'0000
++#
++# we load ourself to 33F8'0000
++#
++# download area is 3300'0000
++#
++
++
++TEXT_BASE = 0x33F80000
+diff -Nuar u-boot-2010.09/board/lingyun/fl2440/fl2440.c u-boot-2010.09-fl2440/board/lingyun/fl2440/fl2440.c
+--- u-boot-2010.09/board/lingyun/fl2440/fl2440.c	1970-01-01 08:00:00.000000000 +0800
++++ u-boot-2010.09-fl2440/board/lingyun/fl2440/fl2440.c	2020-01-09 17:22:17.705412170 +0800
+@@ -0,0 +1,174 @@
++/*
++ * (C) Copyright 2002
++ * Sysgo Real-Time Solutions, GmbH <www.elinos.com>
++ * Marius Groeger <mgroeger@sysgo.de>
++ *
++ * (C) Copyright 2002
++ * David Mueller, ELSOFT AG, <d.mueller@elsoft.ch>
++ *
++ * See file CREDITS for list of people who contributed to this
++ * project.
++ *
++ * This program is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU General Public License as
++ * published by the Free Software Foundation; either version 2 of
++ * the License, or (at your option) any later version.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
++ * MA 02111-1307 USA
++ */
++
++#include <common.h>
++#include <netdev.h>
++#include <asm/arch/s3c24x0_cpu.h>
++
++DECLARE_GLOBAL_DATA_PTR;
++
++#define FCLK_SPEED 1
++
++#if FCLK_SPEED==0		/* Fout = 203MHz, Fin = 12MHz for Audio */
++#define M_MDIV	0xC3
++#define M_PDIV	0x4
++#define M_SDIV	0x1
++#elif FCLK_SPEED==1     /* Fout = 405MHz, modify by guowenxue */
++#define M_MDIV 0x7f 
++#define M_PDIV 0x2
++#define M_SDIV 0x1
++#endif
++
++#define USB_CLOCK 1
++
++#if USB_CLOCK==0
++#define U_M_MDIV	0xA1
++#define U_M_PDIV	0x3
++#define U_M_SDIV	0x1
++#elif USB_CLOCK==1
++#define U_M_MDIV	0x38 /* Modify by guowenxue */
++#define U_M_PDIV	0x3
++#define U_M_SDIV	0x2
++#endif
++
++static inline void delay (unsigned long loops)
++{
++	__asm__ volatile ("1:\n"
++	  "subs %0, %1, #1\n"
++	  "bne 1b":"=r" (loops):"0" (loops));
++}
++
++#ifdef CONFIG_FL2440_BEEP /* Add by guowenxue, 2012.10.04 */
++#define BEEP         0    /* Buzzer use GPB0 */
++#define DELAY_TIME   10000000
++
++void turn_beep(void)
++{
++    int                  count = 2;
++    struct s3c24x0_gpio * const gpio = s3c24x0_get_base_gpio();
++
++    gpio->GPBCON = (gpio->GPBCON|0x3)&0x1; /*  Set GPB0 as GPIO output mode(0x01) */
++
++    while(count--)
++    {
++        gpio->GPBCON = (gpio->GPBCON|0x3)&0x1; /*  Set GPB0 as GPIO output mode(0x01) */
++
++        gpio->GPBDAT &= ~(1<<BEEP);  /*  Set Beep GPIO as low level */
++        delay(DELAY_TIME);
++
++        gpio->GPBDAT |= 1<<BEEP;     /*  Set Beep GPIO as high level */
++        delay(DELAY_TIME);
++
++        gpio->GPBCON &= ~0x3; /*  Set GPB0 as GPIO input mode(0x00) */
++    }
++
++    return ;
++}
++#endif
++
++/*
++ * Miscellaneous platform dependent initialisations
++ */
++
++int board_init (void)
++{
++	struct s3c24x0_clock_power * const clk_power =
++					s3c24x0_get_base_clock_power();
++	struct s3c24x0_gpio * const gpio = s3c24x0_get_base_gpio();
++
++	/* to reduce PLL lock time, adjust the LOCKTIME register */
++	clk_power->LOCKTIME = 0xFFFFFF;
++
++	/* configure MPLL */
++	clk_power->MPLLCON = ((M_MDIV << 12) + (M_PDIV << 4) + M_SDIV);
++
++	/* some delay between MPLL and UPLL */
++	delay (4000);
++
++	/* configure UPLL */
++	clk_power->UPLLCON = ((U_M_MDIV << 12) + (U_M_PDIV << 4) + U_M_SDIV);
++
++	/* some delay between MPLL and UPLL */
++	delay (8000);
++
++	/* set up the I/O ports */
++	gpio->GPACON = 0x007FFFFF;
++	gpio->GPBCON = 0x00044555;
++	gpio->GPBUP = 0x000007FF;
++	gpio->GPCCON = 0xAAAAAAAA;
++	gpio->GPCUP = 0x0000FFFF;
++	gpio->GPDCON = 0xAAAAAAAA;
++	gpio->GPDUP = 0x0000FFFF;
++	gpio->GPECON = 0xAAAAAAAA;
++	gpio->GPEUP = 0x0000FFFF;
++	gpio->GPFCON = 0x000055AA;
++	gpio->GPFUP = 0x000000FF;
++	gpio->GPGCON = 0xFF95FFBA;
++	gpio->GPGUP = 0x0000FFFF;
++	gpio->GPHCON = 0x002AFAAA;
++	gpio->GPHUP = 0x000007FF;
++
++	/* arch number of MINI2440-Board */
++	gd->bd->bi_arch_number = MACH_TYPE_MINI2440; /* Modify by guowenxue  */
++
++	/* adress of boot parameters */
++	gd->bd->bi_boot_params = 0x30000100;
++
++	icache_enable();
++	dcache_enable();
++
++#if defined(CONFIG_FL2440_LED) /* Add by guowenxue, 2012.10.04 */
++    gpio->GPBDAT = 0x00000181;
++#endif
++#ifdef CONFIG_FL2440_BEEP /* Add by guowenxue, 2012.10.04 */
++    turn_beep();
++#endif
++
++	return 0;
++}
++
++int dram_init (void)
++{
++	gd->bd->bi_dram[0].start = PHYS_SDRAM_1;
++	gd->bd->bi_dram[0].size = PHYS_SDRAM_1_SIZE;
++
++	return 0;
++}
++
++#ifdef CONFIG_CMD_NET
++int board_eth_init(bd_t *bis)
++{
++	int rc = 0;
++#ifdef CONFIG_CS8900
++	rc = cs8900_initialize(0, CONFIG_CS8900_BASE);
++#endif
++#ifdef CONFIG_DRIVER_DM9000 
++    rc = dm9000_initialize(bis);
++#endif
++	return rc;
++}
++#endif
+diff -Nuar u-boot-2010.09/board/lingyun/fl2440/flash.c u-boot-2010.09-fl2440/board/lingyun/fl2440/flash.c
+--- u-boot-2010.09/board/lingyun/fl2440/flash.c	1970-01-01 08:00:00.000000000 +0800
++++ u-boot-2010.09-fl2440/board/lingyun/fl2440/flash.c	2020-01-09 17:22:17.705412170 +0800
+@@ -0,0 +1,433 @@
++/*
++ * (C) Copyright 2002
++ * Sysgo Real-Time Solutions, GmbH <www.elinos.com>
++ * Alex Zuepke <azu@sysgo.de>
++ *
++ * See file CREDITS for list of people who contributed to this
++ * project.
++ *
++ * This program is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU General Public License as
++ * published by the Free Software Foundation; either version 2 of
++ * the License, or (at your option) any later version.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
++ * MA 02111-1307 USA
++ */
++
++#include <common.h>
++
++ulong myflush (void);
++
++
++#define FLASH_BANK_SIZE	PHYS_FLASH_SIZE
++#define MAIN_SECT_SIZE  0x10000	/* 64 KB */
++
++flash_info_t flash_info[CONFIG_SYS_MAX_FLASH_BANKS];
++
++
++#define CMD_READ_ARRAY		0x000000F0
++#define CMD_UNLOCK1		0x000000AA
++#define CMD_UNLOCK2		0x00000055
++#define CMD_ERASE_SETUP		0x00000080
++#define CMD_ERASE_CONFIRM	0x00000030
++#define CMD_PROGRAM		0x000000A0
++#define CMD_UNLOCK_BYPASS	0x00000020
++
++#define MEM_FLASH_ADDR1		(*(volatile u16 *)(CONFIG_SYS_FLASH_BASE + (0x00000555 << 1)))
++#define MEM_FLASH_ADDR2		(*(volatile u16 *)(CONFIG_SYS_FLASH_BASE + (0x000002AA << 1)))
++
++#define BIT_ERASE_DONE		0x00000080
++#define BIT_RDY_MASK		0x00000080
++#define BIT_PROGRAM_ERROR	0x00000020
++#define BIT_TIMEOUT		0x80000000	/* our flag */
++
++#define READY 1
++#define ERR   2
++#define TMO   4
++
++/*-----------------------------------------------------------------------
++ */
++
++ulong flash_init (void)
++{
++	int i, j;
++	ulong size = 0;
++
++	for (i = 0; i < CONFIG_SYS_MAX_FLASH_BANKS; i++) {
++		ulong flashbase = 0;
++
++		flash_info[i].flash_id =
++#if defined(CONFIG_AMD_LV400)
++			(AMD_MANUFACT & FLASH_VENDMASK) |
++			(AMD_ID_LV400B & FLASH_TYPEMASK);
++#elif defined(CONFIG_AMD_LV800)
++			(AMD_MANUFACT & FLASH_VENDMASK) |
++			(AMD_ID_LV800B & FLASH_TYPEMASK);
++#else
++#error "Unknown flash configured"
++#endif
++			flash_info[i].size = FLASH_BANK_SIZE;
++		flash_info[i].sector_count = CONFIG_SYS_MAX_FLASH_SECT;
++		memset (flash_info[i].protect, 0, CONFIG_SYS_MAX_FLASH_SECT);
++		if (i == 0)
++			flashbase = PHYS_FLASH_1;
++		else
++			panic ("configured too many flash banks!\n");
++		for (j = 0; j < flash_info[i].sector_count; j++) {
++			if (j <= 3) {
++				/* 1st one is 16 KB */
++				if (j == 0) {
++					flash_info[i].start[j] =
++						flashbase + 0;
++				}
++
++				/* 2nd and 3rd are both 8 KB */
++				if ((j == 1) || (j == 2)) {
++					flash_info[i].start[j] =
++						flashbase + 0x4000 + (j -
++								      1) *
++						0x2000;
++				}
++
++				/* 4th 32 KB */
++				if (j == 3) {
++					flash_info[i].start[j] =
++						flashbase + 0x8000;
++				}
++			} else {
++				flash_info[i].start[j] =
++					flashbase + (j - 3) * MAIN_SECT_SIZE;
++			}
++		}
++		size += flash_info[i].size;
++	}
++
++	flash_protect (FLAG_PROTECT_SET,
++		       CONFIG_SYS_FLASH_BASE,
++		       CONFIG_SYS_FLASH_BASE + monitor_flash_len - 1,
++		       &flash_info[0]);
++
++	flash_protect (FLAG_PROTECT_SET,
++		       CONFIG_ENV_ADDR,
++		       CONFIG_ENV_ADDR + CONFIG_ENV_SIZE - 1, &flash_info[0]);
++
++	return size;
++}
++
++/*-----------------------------------------------------------------------
++ */
++void flash_print_info (flash_info_t * info)
++{
++	int i;
++
++	switch (info->flash_id & FLASH_VENDMASK) {
++	case (AMD_MANUFACT & FLASH_VENDMASK):
++		printf ("AMD: ");
++		break;
++	default:
++		printf ("Unknown Vendor ");
++		break;
++	}
++
++	switch (info->flash_id & FLASH_TYPEMASK) {
++	case (AMD_ID_LV400B & FLASH_TYPEMASK):
++		printf ("1x Amd29LV400BB (4Mbit)\n");
++		break;
++	case (AMD_ID_LV800B & FLASH_TYPEMASK):
++		printf ("1x Amd29LV800BB (8Mbit)\n");
++		break;
++	default:
++		printf ("Unknown Chip Type\n");
++		goto Done;
++		break;
++	}
++
++	printf ("  Size: %ld MB in %d Sectors\n",
++		info->size >> 20, info->sector_count);
++
++	printf ("  Sector Start Addresses:");
++	for (i = 0; i < info->sector_count; i++) {
++		if ((i % 5) == 0) {
++			printf ("\n   ");
++		}
++		printf (" %08lX%s", info->start[i],
++			info->protect[i] ? " (RO)" : "     ");
++	}
++	printf ("\n");
++
++      Done:;
++}
++
++/*-----------------------------------------------------------------------
++ */
++
++int flash_erase (flash_info_t * info, int s_first, int s_last)
++{
++	ushort result;
++	int iflag, cflag, prot, sect;
++	int rc = ERR_OK;
++	int chip;
++
++	/* first look for protection bits */
++
++	if (info->flash_id == FLASH_UNKNOWN)
++		return ERR_UNKNOWN_FLASH_TYPE;
++
++	if ((s_first < 0) || (s_first > s_last)) {
++		return ERR_INVAL;
++	}
++
++	if ((info->flash_id & FLASH_VENDMASK) !=
++	    (AMD_MANUFACT & FLASH_VENDMASK)) {
++		return ERR_UNKNOWN_FLASH_VENDOR;
++	}
++
++	prot = 0;
++	for (sect = s_first; sect <= s_last; ++sect) {
++		if (info->protect[sect]) {
++			prot++;
++		}
++	}
++	if (prot)
++		return ERR_PROTECTED;
++
++	/*
++	 * Disable interrupts which might cause a timeout
++	 * here. Remember that our exception vectors are
++	 * at address 0 in the flash, and we don't want a
++	 * (ticker) exception to happen while the flash
++	 * chip is in programming mode.
++	 */
++	cflag = icache_status ();
++	icache_disable ();
++	iflag = disable_interrupts ();
++
++	/* Start erase on unprotected sectors */
++	for (sect = s_first; sect <= s_last && !ctrlc (); sect++) {
++		printf ("Erasing sector %2d ... ", sect);
++
++		/* arm simple, non interrupt dependent timer */
++		reset_timer_masked ();
++
++		if (info->protect[sect] == 0) {	/* not protected */
++			vu_short *addr = (vu_short *) (info->start[sect]);
++
++			MEM_FLASH_ADDR1 = CMD_UNLOCK1;
++			MEM_FLASH_ADDR2 = CMD_UNLOCK2;
++			MEM_FLASH_ADDR1 = CMD_ERASE_SETUP;
++
++			MEM_FLASH_ADDR1 = CMD_UNLOCK1;
++			MEM_FLASH_ADDR2 = CMD_UNLOCK2;
++			*addr = CMD_ERASE_CONFIRM;
++
++			/* wait until flash is ready */
++			chip = 0;
++
++			do {
++				result = *addr;
++
++				/* check timeout */
++				if (get_timer_masked () >
++				    CONFIG_SYS_FLASH_ERASE_TOUT) {
++					MEM_FLASH_ADDR1 = CMD_READ_ARRAY;
++					chip = TMO;
++					break;
++				}
++
++				if (!chip
++				    && (result & 0xFFFF) & BIT_ERASE_DONE)
++					chip = READY;
++
++				if (!chip
++				    && (result & 0xFFFF) & BIT_PROGRAM_ERROR)
++					chip = ERR;
++
++			} while (!chip);
++
++			MEM_FLASH_ADDR1 = CMD_READ_ARRAY;
++
++			if (chip == ERR) {
++				rc = ERR_PROG_ERROR;
++				goto outahere;
++			}
++			if (chip == TMO) {
++				rc = ERR_TIMOUT;
++				goto outahere;
++			}
++
++			printf ("ok.\n");
++		} else {	/* it was protected */
++
++			printf ("protected!\n");
++		}
++	}
++
++	if (ctrlc ())
++		printf ("User Interrupt!\n");
++
++      outahere:
++	/* allow flash to settle - wait 10 ms */
++	udelay_masked (10000);
++
++	if (iflag)
++		enable_interrupts ();
++
++	if (cflag)
++		icache_enable ();
++
++	return rc;
++}
++
++/*-----------------------------------------------------------------------
++ * Copy memory to flash
++ */
++
++static int write_hword (flash_info_t * info, ulong dest, ushort data)
++{
++	vu_short *addr = (vu_short *) dest;
++	ushort result;
++	int rc = ERR_OK;
++	int cflag, iflag;
++	int chip;
++
++	/*
++	 * Check if Flash is (sufficiently) erased
++	 */
++	result = *addr;
++	if ((result & data) != data)
++		return ERR_NOT_ERASED;
++
++
++	/*
++	 * Disable interrupts which might cause a timeout
++	 * here. Remember that our exception vectors are
++	 * at address 0 in the flash, and we don't want a
++	 * (ticker) exception to happen while the flash
++	 * chip is in programming mode.
++	 */
++	cflag = icache_status ();
++	icache_disable ();
++	iflag = disable_interrupts ();
++
++	MEM_FLASH_ADDR1 = CMD_UNLOCK1;
++	MEM_FLASH_ADDR2 = CMD_UNLOCK2;
++	MEM_FLASH_ADDR1 = CMD_UNLOCK_BYPASS;
++	*addr = CMD_PROGRAM;
++	*addr = data;
++
++	/* arm simple, non interrupt dependent timer */
++	reset_timer_masked ();
++
++	/* wait until flash is ready */
++	chip = 0;
++	do {
++		result = *addr;
++
++		/* check timeout */
++		if (get_timer_masked () > CONFIG_SYS_FLASH_ERASE_TOUT) {
++			chip = ERR | TMO;
++			break;
++		}
++		if (!chip && ((result & 0x80) == (data & 0x80)))
++			chip = READY;
++
++		if (!chip && ((result & 0xFFFF) & BIT_PROGRAM_ERROR)) {
++			result = *addr;
++
++			if ((result & 0x80) == (data & 0x80))
++				chip = READY;
++			else
++				chip = ERR;
++		}
++
++	} while (!chip);
++
++	*addr = CMD_READ_ARRAY;
++
++	if (chip == ERR || *addr != data)
++		rc = ERR_PROG_ERROR;
++
++	if (iflag)
++		enable_interrupts ();
++
++	if (cflag)
++		icache_enable ();
++
++	return rc;
++}
++
++/*-----------------------------------------------------------------------
++ * Copy memory to flash.
++ */
++
++int write_buff (flash_info_t * info, uchar * src, ulong addr, ulong cnt)
++{
++	ulong cp, wp;
++	int l;
++	int i, rc;
++	ushort data;
++
++	wp = (addr & ~1);	/* get lower word aligned address */
++
++	/*
++	 * handle unaligned start bytes
++	 */
++	if ((l = addr - wp) != 0) {
++		data = 0;
++		for (i = 0, cp = wp; i < l; ++i, ++cp) {
++			data = (data >> 8) | (*(uchar *) cp << 8);
++		}
++		for (; i < 2 && cnt > 0; ++i) {
++			data = (data >> 8) | (*src++ << 8);
++			--cnt;
++			++cp;
++		}
++		for (; cnt == 0 && i < 2; ++i, ++cp) {
++			data = (data >> 8) | (*(uchar *) cp << 8);
++		}
++
++		if ((rc = write_hword (info, wp, data)) != 0) {
++			return (rc);
++		}
++		wp += 2;
++	}
++
++	/*
++	 * handle word aligned part
++	 */
++	while (cnt >= 2) {
++		data = *((vu_short *) src);
++		if ((rc = write_hword (info, wp, data)) != 0) {
++			return (rc);
++		}
++		src += 2;
++		wp += 2;
++		cnt -= 2;
++	}
++
++	if (cnt == 0) {
++		return ERR_OK;
++	}
++
++	/*
++	 * handle unaligned tail bytes
++	 */
++	data = 0;
++	for (i = 0, cp = wp; i < 2 && cnt > 0; ++i, ++cp) {
++		data = (data >> 8) | (*src++ << 8);
++		--cnt;
++	}
++	for (; i < 2; ++i, ++cp) {
++		data = (data >> 8) | (*(uchar *) cp << 8);
++	}
++
++	return write_hword (info, wp, data);
++}
+diff -Nuar u-boot-2010.09/board/lingyun/fl2440/lowlevel_init.S u-boot-2010.09-fl2440/board/lingyun/fl2440/lowlevel_init.S
+--- u-boot-2010.09/board/lingyun/fl2440/lowlevel_init.S	1970-01-01 08:00:00.000000000 +0800
++++ u-boot-2010.09-fl2440/board/lingyun/fl2440/lowlevel_init.S	2020-01-09 17:22:17.705412170 +0800
+@@ -0,0 +1,198 @@
++/*
++ * Memory Setup stuff - taken from blob memsetup.S
++ *
++ * Copyright (C) 1999 2000 2001 Erik Mouw (J.A.K.Mouw@its.tudelft.nl) and
++ *                     Jan-Derk Bakker (J.D.Bakker@its.tudelft.nl)
++ *
++ * Modified for the Samsung SMDK2410 by
++ * (C) Copyright 2002
++ * David Mueller, ELSOFT AG, <d.mueller@elsoft.ch>
++ *
++ * See file CREDITS for list of people who contributed to this
++ * project.
++ *
++ * This program is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU General Public License as
++ * published by the Free Software Foundation; either version 2 of
++ * the License, or (at your option) any later version.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
++ * MA 02111-1307 USA
++ */
++
++
++#include <config.h>
++#include <version.h>
++
++
++/* some parameters for the board */
++
++/*
++ *
++ * Taken from linux/arch/arm/boot/compressed/head-s3c2410.S
++ *
++ * Copyright (C) 2002 Samsung Electronics SW.LEE  <hitchcar@sec.samsung.com>
++ *
++ */
++
++#define BWSCON	0x48000000
++#define GPBCON                      0x56000010
++#define GPBDAT                      0x56000014
++#define GPBUP                       0x56000018
++
++/* BWSCON */
++#define DW8			(0x0)
++#define DW16			(0x1)
++#define DW32			(0x2)
++#define WAIT			(0x1<<2)
++#define UBLB			(0x1<<3)
++
++#define B1_BWSCON		(DW32)
++#define B2_BWSCON		(DW16)
++#define B3_BWSCON		(DW16 + WAIT + UBLB)
++#define B4_BWSCON		(DW16)
++#define B5_BWSCON		(DW16)
++#define B6_BWSCON		(DW32)
++#define B7_BWSCON		(DW32)
++
++/* BANK0CON */
++#define B0_Tacs			0x0	/*  0clk */
++#define B0_Tcos			0x0	/*  0clk */
++#define B0_Tacc			0x7	/* 14clk */
++#define B0_Tcoh			0x0	/*  0clk */
++#define B0_Tah			0x0	/*  0clk */
++#define B0_Tacp			0x0
++#define B0_PMC			0x0	/* normal */
++
++/* BANK1CON */
++#define B1_Tacs			0x0	/*  0clk */
++#define B1_Tcos			0x0	/*  0clk */
++#define B1_Tacc			0x7	/* 14clk */
++#define B1_Tcoh			0x0	/*  0clk */
++#define B1_Tah			0x0	/*  0clk */
++#define B1_Tacp			0x0
++#define B1_PMC			0x0
++
++#define B2_Tacs			0x0
++#define B2_Tcos			0x0
++#define B2_Tacc			0x7
++#define B2_Tcoh			0x0
++#define B2_Tah			0x0
++#define B2_Tacp			0x0
++#define B2_PMC			0x0
++
++#define B3_Tacs			0x0	/*  0clk */
++#define B3_Tcos			0x3	/*  4clk */
++#define B3_Tacc			0x7	/* 14clk */
++#define B3_Tcoh			0x1	/*  1clk */
++#define B3_Tah			0x0	/*  0clk */
++#define B3_Tacp			0x3     /*  6clk */
++#define B3_PMC			0x0	/* normal */
++
++#define B4_Tacs			0x0	/*  0clk */
++#define B4_Tcos			0x0	/*  0clk */
++#define B4_Tacc			0x7	/* 14clk */
++#define B4_Tcoh			0x0	/*  0clk */
++#define B4_Tah			0x0	/*  0clk */
++#define B4_Tacp			0x0
++#define B4_PMC			0x0	/* normal */
++
++#define B5_Tacs			0x0	/*  0clk */
++#define B5_Tcos			0x0	/*  0clk */
++#define B5_Tacc			0x7	/* 14clk */
++#define B5_Tcoh			0x0	/*  0clk */
++#define B5_Tah			0x0	/*  0clk */
++#define B5_Tacp			0x0
++#define B5_PMC			0x0	/* normal */
++
++/* SDRAM is on HSB bus, so its clock is from HCLK, FCLK=400, HCLK=100; so SDRAM 1clk=10ns */
++
++#define B6_MT           0x3 /*  SDRAM */
++// K4S561632 datasheet: RAS to CAS delay(Trcd) Min value should be 18/20ns, HCLK is 100MHz, so 1clk=10ns
++// EM63A165  datasheet: RAS# to CAS# delay(Trcd) Min value should be 15/20ns, HCLK is 100MHz, so 1clk=10ns
++#define B6_Trcd         0x2 /* 4clk */
++#define B6_SCAN         0x1 /* 9bit */
++
++#define B7_MT			0x3	/* SDRAM */
++#define B7_Trcd			0x1	/* 3clk */
++#define B7_SCAN			0x1	/* 9bit */
++
++/* REFRESH register<0x48000024> parameter */
++#define REFEN           0x1 /*  Refresh enable */
++#define TREFMD          0x0 /*  CBR(CAS before RAS)/Auto refresh */
++
++//                 Trp: Row precharge time
++// K4S561632 datasheet: Min(Trp) value should be 18/20ns;
++// EM63A165 datasheet:  Min value should be 15/20ns;
++#define Trp             0x2 /*  4clk */
++
++//                Trc:  Row cycle time
++// K4S561632 datasheet: Min value should be 60/65ns;
++// EM63A165 datasheet:  Min value should be 60/63ns;
++// S3C2440  datasheet:  REFRESH register describe: SDRAM Row cycle time: Trc=Tsrc+Trp
++#define Tsrc            0x2 /* 6clk, so Trc=Tsrc+Trp=6+3=9clk */
++
++// K4S561632 datasheet: 64ms refresh period (8K Cycle):  64000/8192=7.81us
++// EM63A165  datasheet: 8192 refresh cycles/64ms:        64000/8192=7.81us
++// S3C2440   datasheet: REFRESH Register Refresh period = (2^11-refresh_count+1)/HCLK
++//                      So Refresh count = 2^11 + 1 - 100x7.81 = 1268
++#define REFCNT          1268
++//#define REFCNT          489 /* HCLK=100Mhz, (2048+1-15.6*100) */
++
++
++/**************************************/
++
++_TEXT_BASE:
++	.word	TEXT_BASE
++
++.globl lowlevel_init
++lowlevel_init:
++    ldr r5, =GPBDAT
++    ldr r6, [r5]
++    bic r6, r6, #(1<<8)  
++    str r6, [r5]
++
++	/* memory control configuration */
++	/* make r0 relative the current location so that it */
++	/* reads SMRDATA out of FLASH rather than memory ! */
++	ldr     r0, =SMRDATA
++	ldr	    r1, =lowlevel_init
++	sub	    r0, r0, r1
++    adr     r3, lowlevel_init /* r3 <- current position of code */
++    add     r0, r0, r3
++	ldr	    r1, =BWSCON	/* Bus Width Status Controller */
++	add     r2, r0, #13*4
++
++0:
++	ldr     r3, [r0], #4
++	str     r3, [r1], #4
++	cmp     r2, r0
++	bne     0b
++
++	/* everything is fine now */
++	mov	pc, lr
++
++	.ltorg
++/* the literal pools origin */
++
++SMRDATA:
++    .word (0+(B1_BWSCON<<4)+(B2_BWSCON<<8)+(B3_BWSCON<<12)+(B4_BWSCON<<16)+(B5_BWSCON<<20)+(B6_BWSCON<<24)+(B7_BWSCON<<28))
++    .word ((B0_Tacs<<13)+(B0_Tcos<<11)+(B0_Tacc<<8)+(B0_Tcoh<<6)+(B0_Tah<<4)+(B0_Tacp<<2)+(B0_PMC))
++    .word ((B1_Tacs<<13)+(B1_Tcos<<11)+(B1_Tacc<<8)+(B1_Tcoh<<6)+(B1_Tah<<4)+(B1_Tacp<<2)+(B1_PMC))
++    .word ((B2_Tacs<<13)+(B2_Tcos<<11)+(B2_Tacc<<8)+(B2_Tcoh<<6)+(B2_Tah<<4)+(B2_Tacp<<2)+(B2_PMC))
++    .word ((B3_Tacs<<13)+(B3_Tcos<<11)+(B3_Tacc<<8)+(B3_Tcoh<<6)+(B3_Tah<<4)+(B3_Tacp<<2)+(B3_PMC))
++    .word ((B4_Tacs<<13)+(B4_Tcos<<11)+(B4_Tacc<<8)+(B4_Tcoh<<6)+(B4_Tah<<4)+(B4_Tacp<<2)+(B4_PMC))
++    .word ((B5_Tacs<<13)+(B5_Tcos<<11)+(B5_Tacc<<8)+(B5_Tcoh<<6)+(B5_Tah<<4)+(B5_Tacp<<2)+(B5_PMC))
++    .word ((B6_MT<<15)+(B6_Trcd<<2)+(B6_SCAN))
++    .word ((B7_MT<<15)+(B7_Trcd<<2)+(B7_SCAN))
++    .word ((REFEN<<23)+(TREFMD<<22)+(Trp<<20)+(Tsrc<<18)+REFCNT)
++    .word 0xb2
++    .word 0x30
++    .word 0x30
+diff -Nuar u-boot-2010.09/board/lingyun/fl2440/Makefile u-boot-2010.09-fl2440/board/lingyun/fl2440/Makefile
+--- u-boot-2010.09/board/lingyun/fl2440/Makefile	1970-01-01 08:00:00.000000000 +0800
++++ u-boot-2010.09-fl2440/board/lingyun/fl2440/Makefile	2020-01-09 17:22:17.705412170 +0800
+@@ -0,0 +1,51 @@
++#
++# (C) Copyright 2000-2006
++# Wolfgang Denk, DENX Software Engineering, wd@denx.de.
++#
++# See file CREDITS for list of people who contributed to this
++# project.
++#
++# This program is free software; you can redistribute it and/or
++# modify it under the terms of the GNU General Public License as
++# published by the Free Software Foundation; either version 2 of
++# the License, or (at your option) any later version.
++#
++# This program is distributed in the hope that it will be useful,
++# but WITHOUT ANY WARRANTY; without even the implied warranty of
++# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++# GNU General Public License for more details.
++#
++# You should have received a copy of the GNU General Public License
++# along with this program; if not, write to the Free Software
++# Foundation, Inc., 59 Temple Place, Suite 330, Boston,
++# MA 02111-1307 USA
++#
++
++include $(TOPDIR)/config.mk
++
++LIB	= $(obj)lib$(BOARD).a
++
++COBJS	:= fl2440.o nand_read.o
++SOBJS	:= lowlevel_init.o
++
++SRCS	:= $(SOBJS:.o=.S) $(COBJS:.o=.c)
++OBJS	:= $(addprefix $(obj),$(COBJS))
++SOBJS	:= $(addprefix $(obj),$(SOBJS))
++
++$(LIB):	$(obj).depend $(OBJS) $(SOBJS)
++	$(AR) $(ARFLAGS) $@ $(OBJS) $(SOBJS)
++
++clean:
++	rm -f $(SOBJS) $(OBJS)
++
++distclean:	clean
++	rm -f $(LIB) core *.bak $(obj).depend
++
++#########################################################################
++
++# defines $(obj).depend target
++include $(SRCTREE)/rules.mk
++
++sinclude $(obj).depend
++
++#########################################################################
+diff -Nuar u-boot-2010.09/board/lingyun/fl2440/nand_read.c u-boot-2010.09-fl2440/board/lingyun/fl2440/nand_read.c
+--- u-boot-2010.09/board/lingyun/fl2440/nand_read.c	1970-01-01 08:00:00.000000000 +0800
++++ u-boot-2010.09-fl2440/board/lingyun/fl2440/nand_read.c	2020-01-09 17:22:17.705412170 +0800
+@@ -0,0 +1,212 @@
++/*
++ * nand_read.c: Simple NAND read functions for booting from NAND
++ *
++ * This is used by cpu/arm920/start.S assembler code,
++ * and the board-specific linker script must make sure this
++ * file is linked within the first 4kB of NAND flash.
++ *
++ * Taken from GPLv2 licensed vivi bootloader,
++ * Copyright (C) 2002 MIZI Research, Inc.
++ *
++ * Author: Hwang, Chideok <hwang@mizi.com>
++ * Date  : $Date: 2004/02/04 10:37:37 $
++ *
++ * u-boot integration and bad-block skipping (C) 2006 by OpenMoko, Inc.
++ * Author: Harald Welte <laforge@openmoko.org>
++ */
++
++#include <common.h>
++#include <linux/mtd/nand.h>
++
++
++#define __REGb(x)	(*(volatile unsigned char *)(x))
++#define __REGw(x)	(*(volatile unsigned short *)(x))
++#define __REGi(x)	(*(volatile unsigned int *)(x))
++#define NF_BASE		0x4e000000
++#if defined(CONFIG_S3C2410)
++#define NFCONF		__REGi(NF_BASE + 0x0)
++#define NFCMD		__REGb(NF_BASE + 0x4)
++#define NFADDR		__REGb(NF_BASE + 0x8)
++#define NFDATA		__REGb(NF_BASE + 0xc)
++#define NFSTAT		__REGb(NF_BASE + 0x10)
++#define NFSTAT_BUSY	1
++#define nand_select()	(NFCONF &= ~0x800)
++#define nand_deselect()	(NFCONF |= 0x800)
++#define nand_clear_RnB()	do {} while (0)
++#elif defined(CONFIG_S3C2440) || defined(CONFIG_S3C2442)
++#define NFCONF		__REGi(NF_BASE + 0x0)
++#define NFCONT		__REGi(NF_BASE + 0x4)
++#define NFCMD		__REGb(NF_BASE + 0x8)
++#define NFADDR		__REGb(NF_BASE + 0xc)
++#define NFDATA		__REGb(NF_BASE + 0x10)
++#define NFDATA16	__REGw(NF_BASE + 0x10)
++#define NFSTAT		__REGb(NF_BASE + 0x20)
++#define NFSTAT_BUSY	1
++#define nand_select()	(NFCONT &= ~(1 << 1))
++#define nand_deselect()	(NFCONT |= (1 << 1))
++#define nand_clear_RnB()	(NFSTAT |= (1 << 2))
++#endif
++
++static inline void nand_wait(void)
++{
++	int i;
++
++	while (!(NFSTAT & NFSTAT_BUSY))
++		for (i=0; i<10; i++);
++}
++
++struct boot_nand_t {
++	int page_size;
++	int block_size;
++	int bad_block_offset;
++};
++
++static int is_bad_block(struct boot_nand_t * nand, unsigned long i)
++{
++	unsigned char data;
++	unsigned long page_num;
++
++	nand_clear_RnB();
++	if (nand->page_size == 512) {
++		NFCMD = NAND_CMD_READOOB; /* 0x50 */
++		NFADDR = nand->bad_block_offset & 0xf;
++		NFADDR = (i >> 9) & 0xff;
++		NFADDR = (i >> 17) & 0xff;
++		NFADDR = (i >> 25) & 0xff;
++	} else if (nand->page_size == 2048) {
++		page_num = i >> 11; /* addr / 2048 */
++		NFCMD = NAND_CMD_READ0;
++		NFADDR = nand->bad_block_offset & 0xff;
++		NFADDR = (nand->bad_block_offset >> 8) & 0xff;
++		NFADDR = page_num & 0xff;
++		NFADDR = (page_num >> 8) & 0xff;
++		NFADDR = (page_num >> 16) & 0xff;
++		NFCMD = NAND_CMD_READSTART;
++	} else {
++		return -1;
++	}
++	nand_wait();
++	data = (NFDATA & 0xff);
++	if (data != 0xff)
++		return 1;
++
++	return 0;
++}
++
++static int nand_read_page_ll(struct boot_nand_t * nand, unsigned char *buf, unsigned long addr)
++{
++	unsigned short *ptr16 = (unsigned short *)buf;
++	unsigned int i, page_num;
++
++	nand_clear_RnB();
++
++	NFCMD = NAND_CMD_READ0;
++
++	if (nand->page_size == 512) {
++		/* Write Address */
++		NFADDR = addr & 0xff;
++		NFADDR = (addr >> 9) & 0xff;
++		NFADDR = (addr >> 17) & 0xff;
++		NFADDR = (addr >> 25) & 0xff;
++	} else if (nand->page_size == 2048) {
++		page_num = addr >> 11; /* addr / 2048 */
++		/* Write Address */
++		NFADDR = 0;
++		NFADDR = 0;
++		NFADDR = page_num & 0xff;
++		NFADDR = (page_num >> 8) & 0xff;
++		NFADDR = (page_num >> 16) & 0xff;
++		NFCMD = NAND_CMD_READSTART;
++	} else {
++		return -1;
++	}
++	nand_wait();
++
++#if defined(CONFIG_S3C2410)
++	for (i = 0; i < nand->page_size; i++) {
++		*buf = (NFDATA & 0xff);
++		buf++;
++	}
++#elif defined(CONFIG_S3C2440) || defined(CONFIG_S3C2442)
++	for (i = 0; i < (nand->page_size>>1); i++) {
++		*ptr16 = NFDATA16;
++		ptr16++;
++	}
++#endif
++
++	return nand->page_size;
++}
++
++static unsigned short nand_read_id()
++{
++	unsigned short res = 0;
++	NFCMD = NAND_CMD_READID;
++	NFADDR = 0;
++	res = NFDATA;
++	res = (res << 8) | NFDATA;
++	return res;
++}
++
++extern unsigned int dynpart_size[];
++
++/* low level nand read function */
++int nand_read_ll(unsigned char *buf, unsigned long start_addr, int size)
++{
++	int i, j;
++	unsigned short nand_id;
++	struct boot_nand_t nand;
++
++	/* chip Enable */
++	nand_select();
++	nand_clear_RnB();
++	
++	for (i = 0; i < 10; i++)
++		;
++	nand_id = nand_read_id();
++	if (0) { /* dirty little hack to detect if nand id is misread */
++		unsigned short * nid = (unsigned short *)0x31fffff0;
++		*nid = nand_id;
++	}	
++
++       if (nand_id == 0xec76 ||		/* Samsung K91208 on SD2410 board */
++           nand_id == 0xad76 ) {	/*Hynix HY27US08121A*/
++		nand.page_size = 512;
++		nand.block_size = 16 * 1024;
++		nand.bad_block_offset = 5;
++	//	nand.size = 0x4000000;
++	} else if (nand_id == 0xecf1 ||	/* Samsung K9F1G08U0B */
++           nand_id == 0xadda || /*  Hynix HY27UF082G2B on FL2440 board */
++		   nand_id == 0xecda ||	/* Samsung K9F2G08U0B on FL2440 board */
++		   nand_id == 0xecd3 )	{ /* Samsung K9K8G08 */
++		nand.page_size = 2048;
++		nand.block_size = 128 * 1024;
++		nand.bad_block_offset = nand.page_size;
++	//	nand.size = 0x8000000;
++	} else {
++		return -1; // hang
++	}
++	if ((start_addr & (nand.block_size-1)) || (size & ((nand.block_size-1))))
++		return -1;	/* invalid alignment */
++
++	for (i=start_addr; i < (start_addr + size);) {
++#ifdef CONFIG_S3C2410_NAND_SKIP_BAD
++		if (i & (nand.block_size-1)== 0) {
++			if (is_bad_block(&nand, i) ||
++			    is_bad_block(&nand, i + nand.page_size)) {
++				/* Bad block */
++				i += nand.block_size;
++				size += nand.block_size;
++				continue;
++			}
++		}
++#endif
++		j = nand_read_page_ll(&nand, buf, i);
++		i += j;
++		buf += j;
++	}
++
++	/* chip Disable */
++	nand_deselect();
++
++	return 0;
++}
+diff -Nuar u-boot-2010.09/boards.cfg u-boot-2010.09-fl2440/boards.cfg
+--- u-boot-2010.09/boards.cfg	2010-09-29 05:20:55.000000000 +0800
++++ u-boot-2010.09-fl2440/boards.cfg	2020-01-09 17:22:17.709412170 +0800
+@@ -238,6 +238,7 @@
+ sbc2410x	arm	arm920t		-		-		s3c24x0
+ smdk2400	arm	arm920t		-		samsung		s3c24x0
+ smdk2410	arm	arm920t		-		samsung		s3c24x0
++fl2440  	arm	arm920t		fl2440	lingyun		s3c24x0
+ voiceblue	arm	arm925t
+ omap1510inn	arm	arm925t		-		ti
+ afeb9260	arm	arm926ejs	-		-		at91
+diff -Nuar u-boot-2010.09/build.sh u-boot-2010.09-fl2440/build.sh
+--- u-boot-2010.09/build.sh	1970-01-01 08:00:00.000000000 +0800
++++ u-boot-2010.09-fl2440/build.sh	2020-01-09 17:25:25.785415778 +0800
+@@ -0,0 +1,72 @@
++#!/bin/bash
++
++BOARD=fl2440
++TFTP_PATH=/tftp
++IMGS_PATH=../images
++IMG_NAME=u-boot-${BOARD}.bin
++
++CROSSTOOL=/opt/buildroot/cortex-a5/bin/arm-linux-
++JOBS=`cat /proc/cpuinfo |grep "processor"|wc -l`
++
++
++function do_clean()
++{
++    make CROSS_COMPILE=${CROSSTOOL} distclean
++    rm -f tools/logos/logo.bmp
++    rm -f cscope* tags
++    rm -f ${IMG_NAME}
++}
++
++function do_modify()
++{
++    grep "arm-linux-gnueabi" Makefile > /dev/null
++
++    if [ $? == 0  ] ; then
++        return ;
++    fi
++
++    echo "Modify Makefile for  ARCH and cross compiler"
++    sed -i -e "s|^CROSS_COMPILE=.*|CROSS_COMPILE=${CROSSTOOL}|g" Makefile
++}
++
++function do_build()
++{
++    make fl2440_config
++
++    make -j${JOBS}
++
++    if [ ! -f ${IMG_NAME} ] ; then
++       mv u-boot-*.bin ${IMG_NAME}
++    fi
++
++    chmod a+x ${IMG_NAME}
++}
++
++function do_install()
++{
++    if [ -w $TFTP_PATH ] ;then 
++        echo "cp ${IMG_NAME} $TFTP_PATH"
++        cp ${IMG_NAME} $TFTP_PATH
++    fi
++
++    if [ -w ${IMGS_PATH} ] ; then
++        echo "cp ${IMG_NAME} $IMGS_PATH"
++        cp ${IMG_NAME} $IMGS_PATH
++    fi
++}
++
++if [ "$1" == "clean" ] ; then 
++
++    do_clean
++    exit 0;
++fi
++
++do_modify
++
++set -e
++
++do_build
++
++do_install
++
++
+diff -Nuar u-boot-2010.09/common/cmd_nand.c u-boot-2010.09-fl2440/common/cmd_nand.c
+--- u-boot-2010.09/common/cmd_nand.c	2010-09-29 05:20:55.000000000 +0800
++++ u-boot-2010.09-fl2440/common/cmd_nand.c	2020-01-09 17:22:17.709412170 +0800
+@@ -148,6 +148,11 @@
+ #if defined(CONFIG_CMD_MTDPARTS)
+ out:
+ #endif
++    /* If the size is not aligment, then let it's page alignment */
++    if(0 != (*size%nand->writesize)) 
++    {
++        *size = (*size / nand->writesize + 1) * nand->writesize;  
++    }
+ 	printf("device %d ", idx);
+ 	if (*size == nand->size)
+ 		puts("whole chip\n");
+diff -Nuar u-boot-2010.09/common/env_common.c u-boot-2010.09-fl2440/common/env_common.c
+--- u-boot-2010.09/common/env_common.c	2010-09-29 05:20:55.000000000 +0800
++++ u-boot-2010.09-fl2440/common/env_common.c	2020-01-09 17:22:17.709412170 +0800
+@@ -57,7 +57,34 @@
+ 	"bootargs="	CONFIG_BOOTARGS			"\0"
+ #endif
+ #ifdef	CONFIG_BOOTCOMMAND
+-	"bootcmd="	CONFIG_BOOTCOMMAND		"\0"
++    "bootcmd="	CONFIG_BOOTCOMMAND		"\0"
++#endif
++#ifdef CONFIG_BBL_COMMAND /* Add by guowenxue, burn u-boot image */
++   "bbl="  CONFIG_BBL_COMMAND      "\0"
++#endif
++#ifdef CONFIG_BLX_COMMAND /* Add by guowenxue, burn linux kernel image */
++   "blx="  CONFIG_BLX_COMMAND      "\0"
++#endif
++#ifdef CONFIG_BURN_UBIFS   /* Add by guowenxue, burn UBIFS root filesystem image */
++   "bubifs=" CONFIG_BURN_UBIFS "\0" 
++#endif 
++#ifdef CONFIG_BURN_JFFS2   /* Add by guowenxue, burn JFFS2 root filesystem image */
++   "bjffs2=" CONFIG_BURN_JFFS2 "\0" 
++#endif
++#ifdef CONFIG_BSYS_COMMAND /* Add by guowenxue, burn linux kernel and rootfs */
++   "bsys="   CONFIG_BSYS_COMMAND     "\0"
++#endif
++#ifdef CONFIG_BARGS_INITRAMFS /* Add by guowenxue, bootargs for initramfs rootfs  */
++   "args_initramfs="   CONFIG_BARGS_INITRAMFS     "\0"
++#endif
++#ifdef CONFIG_BARGS_UBIFS /* Add by guowenxue, bootargs for ubifs rootfs  */
++   "args_ubifs="   CONFIG_BARGS_UBIFS     "\0"
++#endif
++#ifdef CONFIG_BARGS_JFFS2 /* Add by guowenxue, bootargs for jffs2 rootfs  */
++   "args_jffs2="   CONFIG_BARGS_JFFS2     "\0"
++#endif
++#ifdef CONFIG_TFTPBOOT_COMMAND /* Add by guowenxue, tftp boot linux system */
++   "tb="   CONFIG_TFTPBOOT_COMMAND     "\0"
+ #endif
+ #ifdef	CONFIG_RAMBOOTCOMMAND
+ 	"ramboot="	CONFIG_RAMBOOTCOMMAND		"\0"
+diff -Nuar u-boot-2010.09/common/serial.c u-boot-2010.09-fl2440/common/serial.c
+--- u-boot-2010.09/common/serial.c	2010-09-29 05:20:55.000000000 +0800
++++ u-boot-2010.09-fl2440/common/serial.c	2020-01-09 17:22:17.709412170 +0800
+@@ -68,7 +68,7 @@
+ #else
+ #error "Bad CONFIG_PSC_CONSOLE."
+ #endif
+-#elif defined(CONFIG_S3C2410)
++#elif defined(CONFIG_S3C2410) || defined(CONFIG_S3C2440)
+ #if defined(CONFIG_SERIAL1)
+ 	return &s3c24xx_serial0_device;
+ #elif defined(CONFIG_SERIAL2)
+@@ -157,7 +157,7 @@
+ #if defined (CONFIG_STUART)
+ 	serial_register(&serial_stuart_device);
+ #endif
+-#if defined(CONFIG_S3C2410)
++#if defined(CONFIG_S3C2410) || defined(CONFIG_S3C2440)
+ 	serial_register(&s3c24xx_serial0_device);
+ 	serial_register(&s3c24xx_serial1_device);
+ 	serial_register(&s3c24xx_serial2_device);
+diff -Nuar u-boot-2010.09/drivers/mtd/nand/s3c2410_nand.c u-boot-2010.09-fl2440/drivers/mtd/nand/s3c2410_nand.c
+--- u-boot-2010.09/drivers/mtd/nand/s3c2410_nand.c	2010-09-29 05:20:55.000000000 +0800
++++ u-boot-2010.09-fl2440/drivers/mtd/nand/s3c2410_nand.c	2020-01-09 17:22:17.709412170 +0800
+@@ -24,6 +24,7 @@
+ #include <asm/arch/s3c24x0_cpu.h>
+ #include <asm/io.h>
+ 
++#if defined(CONFIG_S3C2410)
+ #define S3C2410_NFCONF_EN          (1<<15)
+ #define S3C2410_NFCONF_512BYTE     (1<<14)
+ #define S3C2410_NFCONF_4STEP       (1<<13)
+@@ -36,6 +37,20 @@
+ #define S3C2410_ADDR_NALE 4
+ #define S3C2410_ADDR_NCLE 8
+ 
++#elif defined(CONFIG_S3C2440)
++#define S3C2410_NFCONT_EN          (1<<0)
++#define S3C2410_NFCONT_INITECC     (1<<4)
++#define S3C2410_NFCONT_nFCE        (1<<1)
++#define S3C2410_NFCONT_MAINECCLOCK (1<<5)
++#define S3C2410_NFCONF_TACLS(x)    ((x)<<12)
++#define S3C2410_NFCONF_TWRPH0(x)   ((x)<<8)
++#define S3C2410_NFCONF_TWRPH1(x)   ((x)<<4)
++
++#define S3C2410_ADDR_NALE 0x08
++#define S3C2410_ADDR_NCLE 0x0c
++#endif
++ulong IO_ADDR_W = CONFIG_SYS_NAND_BASE;
++
+ #ifdef CONFIG_NAND_SPL
+ 
+ /* in the early stage of NAND flash booting, printf() is not available */
+@@ -59,25 +74,31 @@
+ 	debugX(1, "hwcontrol(): 0x%02x 0x%02x\n", cmd, ctrl);
+ 
+ 	if (ctrl & NAND_CTRL_CHANGE) {
+-		ulong IO_ADDR_W = (ulong)nand;
++		IO_ADDR_W = (ulong)nand;
+ 
+ 		if (!(ctrl & NAND_CLE))
+ 			IO_ADDR_W |= S3C2410_ADDR_NCLE;
+ 		if (!(ctrl & NAND_ALE))
+ 			IO_ADDR_W |= S3C2410_ADDR_NALE;
+ 
+-		chip->IO_ADDR_W = (void *)IO_ADDR_W;
++		//chip->IO_ADDR_W = (void *)IO_ADDR_W;
+ 
+ 		if (ctrl & NAND_NCE)
+-			writel(readl(&nand->NFCONF) & ~S3C2410_NFCONF_nFCE,
+-			       &nand->NFCONF);
++#if defined(CONFIG_S3C2410)
++			writel(readl(&nand->NFCONF) & ~S3C2410_NFCONF_nFCE, &nand->NFCONF);
++#elif defined(CONFIG_S3C2440)
++            writel(readl(&nand->NFCONT) & ~S3C2410_NFCONT_nFCE, &nand->NFCONT);
++#endif
+ 		else
+-			writel(readl(&nand->NFCONF) | S3C2410_NFCONF_nFCE,
+-			       &nand->NFCONF);
++#if defined(CONFIG_S3C2410)
++			writel(readl(&nand->NFCONF) | S3C2410_NFCONF_nFCE, &nand->NFCONF);
++#elif defined(CONFIG_S3C2440)
++            writel(readl(&nand->NFCONT) | S3C2410_NFCONT_nFCE, &nand->NFCONT);
++#endif
+ 	}
+ 
+ 	if (cmd != NAND_CMD_NONE)
+-		writeb(cmd, chip->IO_ADDR_W);
++        writeb(cmd, (void *)IO_ADDR_W);
+ }
+ 
+ static int s3c2410_dev_ready(struct mtd_info *mtd)
+@@ -92,7 +113,11 @@
+ {
+ 	struct s3c2410_nand *nand = s3c2410_get_base_nand();
+ 	debugX(1, "s3c2410_nand_enable_hwecc(%p, %d)\n", mtd, mode);
++#if defined(CONFIG_S3C2410)
+ 	writel(readl(&nand->NFCONF) | S3C2410_NFCONF_INITECC, &nand->NFCONF);
++#elif defined(CONFIG_S3C2440)
++    writel(readl(&nand->NFCONT) | S3C2410_NFCONT_INITECC, &nand->NFCONT);
++#endif
+ }
+ 
+ static int s3c2410_nand_calculate_ecc(struct mtd_info *mtd, const u_char *dat,
+@@ -132,6 +157,7 @@
+ 
+ 	writel(readl(&clk_power->CLKCON) | (1 << 4), &clk_power->CLKCON);
+ 
++#if defined(CONFIG_S3C2410)
+ 	/* initialize hardware */
+ 	twrph0 = 3;
+ 	twrph1 = 0;
+@@ -145,6 +171,20 @@
+ 
+ 	/* initialize nand_chip data structure */
+ 	nand->IO_ADDR_R = nand->IO_ADDR_W = (void *)&nand_reg->NFDATA;
++#elif defined(CONFIG_S3C2440) 
++    twrph0 = 4; 
++    twrph1 = 2; 
++    tacls = 0; 
++    cfg = 0;
++    cfg |= S3C2410_NFCONF_TACLS(tacls - 1);
++    cfg |= S3C2410_NFCONF_TWRPH0(twrph0 - 1);
++    cfg |= S3C2410_NFCONF_TWRPH1(twrph1 - 1);
++    writel(cfg, &nand_reg->NFCONF); 
++    cfg = (0<<13)|(0<<12)|(0<<10)|(0<<9)|(0<<8)|(0<<6)|(0<<5)|(1<<4)|(0<<1)|(1<<0);
++    writel(cfg, &nand_reg->NFCONT);
++    /*  initialize nand_chip data structure */
++    nand->IO_ADDR_R = nand->IO_ADDR_W = (void *)&nand_reg->NFDATA;
++#endif
+ 
+ 	nand->select_chip = NULL;
+ 
+diff -Nuar u-boot-2010.09/drivers/net/dm9000x.c u-boot-2010.09-fl2440/drivers/net/dm9000x.c
+--- u-boot-2010.09/drivers/net/dm9000x.c	2010-09-29 05:20:55.000000000 +0800
++++ u-boot-2010.09-fl2440/drivers/net/dm9000x.c	2020-01-09 17:22:17.709412170 +0800
+@@ -364,7 +364,7 @@
+ 	while (!(phy_read(1) & 0x20)) {	/* autonegation complete bit */
+ 		udelay(1000);
+ 		i++;
+-		if (i == 10000) {
++		if (i == 2000) { /* Modify by guowenxue */
+ 			printf("could not establish link\n");
+ 			return 0;
+ 		}
+diff -Nuar u-boot-2010.09/include/configs/fl2440.h u-boot-2010.09-fl2440/include/configs/fl2440.h
+--- u-boot-2010.09/include/configs/fl2440.h	1970-01-01 08:00:00.000000000 +0800
++++ u-boot-2010.09-fl2440/include/configs/fl2440.h	2020-01-09 17:22:17.709412170 +0800
+@@ -0,0 +1,239 @@
++/*
++ * (C) Copyright 2002
++ * Sysgo Real-Time Solutions, GmbH <www.elinos.com>
++ * Marius Groeger <mgroeger@sysgo.de>
++ * Gary Jennejohn <garyj@denx.de>
++ * David Mueller <d.mueller@elsoft.ch>
++ *
++ * Configuation settings for the SAMSUNG SMDK2410 board.
++ *
++ * See file CREDITS for list of people who contributed to this
++ * project.
++ *
++ * This program is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU General Public License as
++ * published by the Free Software Foundation; either version 2 of
++ * the License, or (at your option) any later version.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
++ * MA 02111-1307 USA
++ */
++
++#ifndef __CONFIG_H
++#define __CONFIG_H
++
++/*
++ * High Level Configuration Options
++ * (easy to change)
++ */
++#define CONFIG_ARM920T	1	/* This is an ARM920T Core	*/
++#define CONFIG_S3C24X0	1	/* in a SAMSUNG S3C24x0-type SoC	*/
++#define CONFIG_S3C2440  1   /*  specifically a SAMSUNG S3C2440 SoC   */ 
++#define CONFIG_FL2440   1   /*  FL2440 board */ 
++
++#define CONFIG_FL2440_LED               1
++#define CONFIG_FL2440_BEEP              1
++#define CONFIG_S3C2410_NAND_SKIP_BAD    1
++
++/* input clock of PLL */
++#define CONFIG_SYS_CLK_FREQ	12000000/* the SMDK2410 has 12MHz input clock */
++
++
++#define USE_920T_MMU		1
++#undef CONFIG_USE_IRQ			/* we don't need IRQ/FIQ stuff */
++
++/*
++ * Size of malloc() pool
++ */
++#define CONFIG_SYS_MALLOC_LEN		(CONFIG_ENV_SIZE + 128*1024)
++#define CONFIG_SYS_GBL_DATA_SIZE	128	/* size in bytes reserved for initial data */
++
++/*
++ * Hardware drivers
++ */
++#define CONFIG_NET_MULTI            1
++#define CONFIG_NET_RETRY_COUNT      20
++#define CONFIG_DRIVER_DM9000        1
++#define CONFIG_DM9000_BASE          0x20000300  /*  nGCS4 */
++#define DM9000_IO                   CONFIG_DM9000_BASE
++#define DM9000_DATA                 (CONFIG_DM9000_BASE+4)
++#define CONFIG_DM9000_USE_16BIT     1
++#define CONFIG_DM9000_NO_SROM       1
++#undef CONFIG_DM9000_DEBUG
++
++/*
++ * select serial console configuration
++ */
++#define CONFIG_S3C24X0_SERIAL
++#define CONFIG_SERIAL1          1	/* we use SERIAL 1 on SMDK2410 */
++
++/************************************************************
++ * RTC
++ ************************************************************/
++#define	CONFIG_RTC_S3C24X0	1
++
++/* allow to overwrite serial and ethaddr */
++#define CONFIG_ENV_OVERWRITE
++
++#define CONFIG_BAUDRATE		115200
++
++
++/*
++ * BOOTP options
++ */
++#define CONFIG_BOOTP_BOOTFILESIZE
++#define CONFIG_BOOTP_BOOTPATH
++#define CONFIG_BOOTP_GATEWAY
++#define CONFIG_BOOTP_HOSTNAME
++
++
++/*
++ * Command line configuration.
++ */
++#include <config_cmd_default.h>
++
++#define CONFIG_CMD_CACHE
++#define CONFIG_CMD_DATE
++#define CONFIG_CMD_ELF
++#define CONFIG_CMD_PING
++#define CONFIG_CMD_NAND
++
++
++#define CONFIG_BOOTDELAY	2
++#define CONFIG_ETHADDR      08:00:3e:26:0a:5b 
++#define CONFIG_NETMASK      255.255.255.0
++#define CONFIG_IPADDR       192.168.2.168
++#define CONFIG_SERVERIP     192.168.2.8
++
++
++#define CONFIG_BBL_COMMAND      "tftp 30008000 u-boot-fl2440.bin;nand erase 0 100000;nand write 30008000 0 60000"
++#define CONFIG_BLX_COMMAND      "tftp 30008000 linuxrom-fl2440.bin;nand erase 100000 F00000;nand write 30008000 100000 D00000"
++#define CONFIG_BSYS_COMMAND     "run blx;run bubifs"
++#define CONFIG_TFTPBOOT_COMMAND "tftp 30008000 linuxrom-fl2440.bin; bootm 30008000"
++#define CONFIG_BURN_JFFS2       "tftp 30008000 rootfs-fl2440.jfs;nand erase 1000000 2800000;nand write 30008000 1000000 $filesize"
++#define CONFIG_BURN_UBIFS       "tftp 30008000 rootfs-fl2440.ubi;nand erase 1000000 2800000;nand write 30008000 1000000 $filesize"
++
++
++#define CONFIG_BARGS_INITRAMFS  "console=tty0 console=ttyS0,115200 mem=64M rw loglevel=7"
++#define CONFIG_BARGS_JFFS2      "console=tty0 console=ttyS0,115200 root=/dev/mtdblock2 rootfstype=jffs2 init=/linuxrc mem=64M rw noinitrd loglevel=7"
++#define CONFIG_BARGS_UBIFS      "console=tty0 console=ttyS0,115200 ubi.mtd=2 root=ubi0:rootfs rootfstype=ubifs mem=64M noinitrd rw loglevel=7"
++#define CONFIG_BOOTARGS         CONFIG_BARGS_UBIFS
++#define CONFIG_BOOTCOMMAND     "nand read 30008000 100000 900000; bootm 30008000"
++
++#if defined(CONFIG_CMD_KGDB)
++#define CONFIG_KGDB_BAUDRATE	115200		/* speed to run kgdb serial port */
++/* what's this ? it's not used anywhere */
++#define CONFIG_KGDB_SER_INDEX	1		/* which serial port to use */
++#endif
++
++/*
++ * Miscellaneous configurable options
++ */
++#define	CONFIG_SYS_LONGHELP				/* undef to save memory		*/
++#define	CONFIG_SYS_PROMPT		"[fl2440@lingyun]# "	/* Monitor Command Prompt	*/
++#define	CONFIG_SYS_CBSIZE		256		/* Console I/O Buffer Size	*/
++#define	CONFIG_SYS_PBSIZE (CONFIG_SYS_CBSIZE+sizeof(CONFIG_SYS_PROMPT)+16) /* Print Buffer Size */
++#define	CONFIG_SYS_MAXARGS		16		/* max number of command args	*/
++#define CONFIG_SYS_BARGSIZE		CONFIG_SYS_CBSIZE	/* Boot Argument Buffer Size	*/
++
++#define CONFIG_SYS_MEMTEST_START	0x30000000	/* memtest works on	*/
++#define CONFIG_SYS_MEMTEST_END		0x33F00000	/* 63 MB in DRAM	*/
++
++#define	CONFIG_SYS_LOAD_ADDR		0x33000000	/* default load address	*/
++
++#define	CONFIG_SYS_HZ			1000
++
++/* valid baudrates */
++#define CONFIG_SYS_BAUDRATE_TABLE	{ 9600, 19200, 38400, 57600, 115200 }
++
++/*-----------------------------------------------------------------------
++ * Stack sizes
++ *
++ * The stack sizes are set up in start.S using the settings below
++ */
++#define CONFIG_STACKSIZE	(128*1024)	/* regular stack */
++#ifdef CONFIG_USE_IRQ
++#define CONFIG_STACKSIZE_IRQ	(4*1024)	/* IRQ stack */
++#define CONFIG_STACKSIZE_FIQ	(4*1024)	/* FIQ stack */
++#endif
++
++/*-----------------------------------------------------------------------
++ * Physical Memory Map
++ */
++#define CONFIG_NR_DRAM_BANKS	1	   /* we have 1 bank of DRAM */
++#define PHYS_SDRAM_1		0x30000000 /* SDRAM Bank #1 */
++#define PHYS_SDRAM_1_SIZE	0x04000000 /* 64 MB */
++
++#define PHYS_FLASH_1		0x00000000 /* Flash Bank #1 */
++
++#define CONFIG_SYS_FLASH_BASE		PHYS_FLASH_1
++
++#define CONFIG_SYS_NO_FLASH         1
++#undef  CONFIG_CMD_IMLS
++
++/*-----------------------------------------------------------------------
++ * FLASH and environment organization
++ */
++#ifndef CONFIG_SYS_NO_FLASH
++#define CONFIG_AMD_LV400	1	/* uncomment this if you have a LV400 flash */
++#endif
++#if 0
++#define CONFIG_AMD_LV800	1	/* uncomment this if you have a LV800 flash */
++#endif
++
++#define CONFIG_SYS_MAX_FLASH_BANKS	1	/* max number of memory banks */
++#ifdef CONFIG_AMD_LV800
++#define PHYS_FLASH_SIZE		0x00100000 /* 1MB */
++#define CONFIG_SYS_MAX_FLASH_SECT	(19)	/* max number of sectors on one chip */
++#define CONFIG_ENV_ADDR		(CONFIG_SYS_FLASH_BASE + 0x0F0000) /* addr of environment */
++#endif
++#ifdef CONFIG_AMD_LV400
++#define PHYS_FLASH_SIZE		0x00080000 /* 512KB */
++#define CONFIG_SYS_MAX_FLASH_SECT	(11)	/* max number of sectors on one chip */
++#define CONFIG_ENV_ADDR		(CONFIG_SYS_FLASH_BASE + 0x070000) /* addr of environment */
++#endif
++
++/* timeout values are in ticks */
++#define CONFIG_SYS_FLASH_ERASE_TOUT	(5*CONFIG_SYS_HZ) /* Timeout for Flash Erase */
++#define CONFIG_SYS_FLASH_WRITE_TOUT	(5*CONFIG_SYS_HZ) /* Timeout for Flash Write */
++
++#ifndef CONFIG_SYS_NO_FLASH
++#define	CONFIG_ENV_IS_IN_FLASH	1
++#define CONFIG_ENV_SIZE		0x10000	/* Total Size of Environment Sector */
++#endif
++
++#if defined(CONFIG_CMD_NAND) 
++#define CONFIG_NAND_S3C2410 
++#define CONFIG_S3C2410_NAND_SKIP_BAD  1 
++#define CONFIG_SYS_NAND_BASE          0x4E000000 
++#define CONFIG_SYS_MAX_NAND_DEVICE    1   /* Max number of NAND devices */ 
++#define CONFIG_SYS_NAND_MAX_CHIPS     1
++#define CONFIG_MTD_NAND_VERIFY_WRITE 
++
++#define CONFIG_ENV_IS_IN_NAND   1 
++#define CONFIG_ENV_OFFSET       0X60000 
++#define CONFIG_ENV_SIZE         0x20000 /* Total Size of Environment Sector */ 
++#endif  /*   CONFIG_CMD_NAND */ 
++
++#define CONFIG_SETUP_MEMORY_TAGS
++#define CONFIG_INITRD_TAG
++#define CONFIG_CMDLINE_TAG
++
++#define CONFIG_SYS_HUSH_PARSER
++#define CONFIG_SYS_PROMPT_HUSH_PS2   "> "
++
++#define CONFIG_CMDLINE_EDITING
++#ifdef CONFIG_CMDLINE_EDITING
++#undef CONFIG_AUTO_COMPLETE
++#else
++#define CONFIG_AUTO_COMPLETE
++#endif
++
++#endif	/* __CONFIG_H */
+diff -Nuar u-boot-2010.09/include/serial.h u-boot-2010.09-fl2440/include/serial.h
+--- u-boot-2010.09/include/serial.h	2010-09-29 05:20:55.000000000 +0800
++++ u-boot-2010.09-fl2440/include/serial.h	2020-01-09 17:22:17.709412170 +0800
+@@ -46,7 +46,7 @@
+ extern struct serial_device serial6_device;
+ #endif
+ 
+-#if defined(CONFIG_S3C2410)
++#if defined(CONFIG_S3C2410) || defined(CONFIG_S3C2440)
+ extern struct serial_device s3c24xx_serial0_device;
+ extern struct serial_device s3c24xx_serial1_device;
+ extern struct serial_device s3c24xx_serial2_device;
+diff -Nuar u-boot-2010.09/Makefile u-boot-2010.09-fl2440/Makefile
+--- u-boot-2010.09/Makefile	2010-09-29 05:20:55.000000000 +0800
++++ u-boot-2010.09-fl2440/Makefile	2020-01-09 17:25:16.141415593 +0800
+@@ -154,6 +154,8 @@
+ # load ARCH, BOARD, and CPU configuration
+ include $(obj)include/config.mk
+ export	ARCH CPU BOARD VENDOR SOC
++export ARCH=arm
++export CROSS_COMPILE=/opt/xtools/arm920t/bin/arm-linux-
+ 
+ # set default to nothing for native builds
+ ifeq ($(HOSTARCH),$(ARCH))
+@@ -317,6 +319,7 @@
+ 
+ $(obj)u-boot.bin:	$(obj)u-boot
+ 		$(OBJCOPY) ${OBJCFLAGS} -O binary $< $@
++		mv u-boot.bin u-boot-fl2440.bin
+ 
+ $(obj)u-boot.ldr:	$(obj)u-boot
+ 		$(CREATE_LDR_ENV)
diff --git a/linux-bsp/patches/u-boot-serial-patch/u-boot-2010.09-1-basic.patch b/linux-bsp/patches/u-boot-serial-patch/u-boot-2010.09-1-basic.patch
new file mode 100644
index 0000000..3a31877
--- /dev/null
+++ b/linux-bsp/patches/u-boot-serial-patch/u-boot-2010.09-1-basic.patch
@@ -0,0 +1,1765 @@
+diff -Nuar u-boot-2010.09/arch/arm/cpu/arm920t/s3c24x0/speed.c u-boot-2010.09-1-basic/arch/arm/cpu/arm920t/s3c24x0/speed.c
+--- u-boot-2010.09/arch/arm/cpu/arm920t/s3c24x0/speed.c	2010-09-29 05:20:55.000000000 +0800
++++ u-boot-2010.09-1-basic/arch/arm/cpu/arm920t/s3c24x0/speed.c	2015-11-16 13:12:18.660998681 +0800
+@@ -64,6 +64,11 @@
+ 	p = ((r & 0x003F0) >> 4) + 2;
+ 	s = r & 0x3;
+ 
++#if defined(CONFIG_S3C2440) /* Add by guowenxue*/
++    if (pllreg == MPLL)
++        return ((CONFIG_SYS_CLK_FREQ * m * 2) /(p << s));
++    else if (pllreg == UPLL)
++#endif /* Add end*/
+ 	return (CONFIG_SYS_CLK_FREQ * m) / (p << s);
+ }
+ 
+@@ -78,7 +83,22 @@
+ {
+ 	struct s3c24x0_clock_power *clk_power = s3c24x0_get_base_clock_power();
+ 
++#if defined(CONFIG_S3C2440) 
++    if (readl(&clk_power->CLKDIVN) & 0x6)
++    {
++        if ((readl(&clk_power->CLKDIVN) & 0x6)==2)
++            return(get_FCLK()/2);
++        if ((readl(&clk_power->CLKDIVN) & 0x6)==6)
++            return((readl(&clk_power->CAMDIVN) & 0x100) ? get_FCLK()/6 : get_FCLK()/3);
++        if ((readl(&clk_power->CLKDIVN) & 0x6)==4)
++            return((readl(&clk_power->CAMDIVN) & 0x200) ? get_FCLK()/8 : get_FCLK()/4);
++        return(get_FCLK());
++    }
++    else
++        return(get_FCLK());
++#else
+ 	return (readl(&clk_power->CLKDIVN) & 2) ? get_FCLK() / 2 : get_FCLK();
++#endif
+ }
+ 
+ /* return PCLK frequency */
+@@ -95,4 +115,17 @@
+ 	return get_PLLCLK(UPLL);
+ }
+ 
++
++#if defined(CONFIG_DISPLAY_CPUINFO)
++int print_cpuinfo(void)
++{   
++    printf("S3C2440A CPU clock   : %lu MHz\n", get_FCLK());
++    printf("S3C2440A HSB clock   : %lu MHz\n", get_HCLK());
++    printf("S3C2440A PSB clock   : %lu MHz\n", get_PCLK());
++    printf("S3C2440A USB clock   : %lu MHz\n", get_FCLK());
++
++    return 0;
++}
++#endif
++
+ #endif /* CONFIG_S3C24X0 */
+diff -Nuar u-boot-2010.09/arch/arm/cpu/arm920t/s3c24x0/timer.c u-boot-2010.09-1-basic/arch/arm/cpu/arm920t/s3c24x0/timer.c
+--- u-boot-2010.09/arch/arm/cpu/arm920t/s3c24x0/timer.c	2010-09-29 05:20:55.000000000 +0800
++++ u-boot-2010.09-1-basic/arch/arm/cpu/arm920t/s3c24x0/timer.c	2015-11-16 13:12:09.988998722 +0800
+@@ -181,6 +181,7 @@
+ 	tbclk = timer_load_val * 100;
+ #elif defined(CONFIG_SBC2410X) || \
+       defined(CONFIG_SMDK2410) || \
++      defined(CONFIG_FL2440) || \
+       defined(CONFIG_VCMA9)
+ 	tbclk = CONFIG_SYS_HZ;
+ #else
+diff -Nuar u-boot-2010.09/arch/arm/cpu/arm920t/start.S u-boot-2010.09-1-basic/arch/arm/cpu/arm920t/start.S
+--- u-boot-2010.09/arch/arm/cpu/arm920t/start.S	2010-09-29 05:20:55.000000000 +0800
++++ u-boot-2010.09-1-basic/arch/arm/cpu/arm920t/start.S	2015-11-16 13:12:09.988998722 +0800
+@@ -114,8 +114,8 @@
+ 	orr	r0, r0, #0xd3
+ 	msr	cpsr, r0
+ 
+-	bl	coloured_LED_init
+-	bl	red_LED_on
++	@bl	coloured_LED_init
++	@bl	red_LED_on
+ 
+ #if	defined(CONFIG_AT91RM9200DK) || defined(CONFIG_AT91RM9200EK)
+ 	/*
+@@ -159,13 +159,63 @@
+ 	ldr	r1, =0x3ff
+ 	ldr	r0, =INTSUBMSK
+ 	str	r1, [r0]
++#elif defined CONFIG_S3C2440
++    ldr     r1, =0x7fff
++    ldr     r0, =INTSUBMSK 
++    str     r1, [r0]
+ # endif
+ 
++# if defined(CONFIG_S3C2440)
++#define GPBCON                      0x56000010
++#define GPBDAT                      0x56000014
++#define GPBUP                       0x56000018
++    /*Set GPIO5, GPIO6, GPIO8, GPIO10 as GPIO OUTPUT mode*/
++    ldr r0, =GPBCON
++    ldr r1, [r0]
++    bic r1, r1, #0x3c00      /*Set GPBCON for GPIO5,GPIO6 as 0x00 */
++    orr r1, r1, #0x1400      /*Set GPBCON for GPIO5,GPIO6 as GPIOOUT, 0x01*/
++    bic r1, r1, #0x00330000  /*Set GPBCON for GPIO8,GPIO10 as 0x00*/
++    orr r1, r1, #0x00110000  /*Set GPBCON for GPIO8,GPIO10 as GPIOOUT, 0x01*/
++    str r1, [r0]
++
++    /*Set internal pullup resister*/ 
++    ldr r0, =GPBUP 
++    ldr r1, [r0] 
++    orr r1, r1, #0x0560     /*Set bit 5,6,8,10, disable pullup resister*/ 
++    str r1, [r0]
++
++    ldr     r2, =GPBDAT
++    ldr     r3, [r2]
++    orr     r3, r3, #0x0560     /*Set bit 5,6,8,10 as high level, Turn Off LED*/
++    str     r3, [r2]
++
++#  define MPLLCON        0x4C000004 
++#  define MDIV_405        0x7f << 12  
++#  define PSDIV_405       0x21         
++
++
++    /* FCLK:HCLK:PCLK = 1:4:8 */
++    ldr r0, =CLKDIVN
++    mov r1, #0x05
++    str r1, [r0]
++
++    mrc p15, 0, r1, c1, c0, 0
++    orr r1, r1, #0xc0000000
++    mcr p15, 0, r1, c1, c0, 0 
++
++    Ldr r0,=MPLLCON
++    mov r1, #MDIV_405
++    add r1, r1, #PSDIV_405
++    str r1, [r0]
++
++
++#else /*S3C2410, S3C2440 */
+ 	/* FCLK:HCLK:PCLK = 1:2:4 */
+ 	/* default FCLK is 120 MHz ! */
+ 	ldr	r0, =CLKDIVN
+ 	mov	r1, #3
+ 	str	r1, [r0]
++#endif /* end of if defined(CONFIG_S3C2440) */
+ #endif	/* CONFIG_S3C24X0 */
+ 
+ 	/*
+@@ -183,6 +233,92 @@
+ 	cmp	r0, r1			/* don't reloc during debug         */
+ 	beq	stack_setup
+ 
++judgment_norflash_nandflash_boot:
++    ldr r1, =( (4<<28)|(3<<4)|(3<<2) ) 
++    mov r0, #0
++    str r0, [r1]
++
++    mov r1, #0x3c
++    ldr r0, [r1]
++    cmp r0, #0
++    bne norflash_boot
++
++    /*Nandflash boot going here, recovery address 0x0000003C date*/
++    ldr r0, =(0xdeadbeef)
++    ldr r1, =( (4<<28)|(3<<4)|(3<<2) )
++    str r0, [r1]
++
++nandflash_boot:
++#define LENGTH_UBOOT 0x60000 
++#define NAND_CTL_BASE 0x4E000000
++/* Offset */
++#define oNFCONF 0x00
++#define oNFCONT 0x04
++#define oNFCMD 0x08
++#define oNFSTAT 0x20
++
++    mov r1, #NAND_CTL_BASE 
++    ldr r2, =( (7<<12)|(7<<8)|(7<<4)|(0<<0) )
++    str r2, [r1, #oNFCONF]
++    ldr r2, [r1, #oNFCONF]
++
++    ldr r2, =( (1<<4)|(0<<1)|(1<<0) )   @ Active low CE Control
++    str r2, [r1, #oNFCONT]
++    ldr r2, [r1, #oNFCONT]
++
++    ldr r2, =(0x6)  @ RnB Clear 
++    str r2, [r1, #oNFSTAT] 
++    ldr r2, [r1, #oNFSTAT]
++
++    mov r2, #0xff   @ RESET command 
++    strb    r2, [r1, #oNFCMD]
++
++    mov r3, #0  @ wait
++nand_delay:
++    add r3, r3, #0x1 
++    cmp r3, #0xa 
++    blt nand_delay
++
++nand_wait:
++    ldr r2, [r1, #oNFSTAT]  @ wait ready 
++    tst r2, #0x4 
++    beq nand_wait
++
++    ldr r2, [r1, #oNFCONT] 
++    orr r2, r2, #0x2    @ Flash Memory Chip Disable 
++    str r2, [r1, #oNFCONT]
++
++    ldr sp, DW_STACK_START  @ setup stack pointer
++    mov fp, #0  @ no previous frame, so fp=0
++
++    ldr r0, =TEXT_BASE 
++    mov r1, #0x0 
++    mov r2, #LENGTH_UBOOT 
++    bl  nand_read_ll 
++    tst r0, #0x0 
++    bne infinite_loop     /*nand_read_ll() not return 0, then goto dead loop*/
++
++nand_read_ok:
++    /*Then verify the read data validation*/
++    mov r0, #0 
++    ldr r1, =TEXT_BASE 
++    mov r2, #0x400  @ 4 bytes * 1024 = 4K-bytes 
++    
++compare_next_byte:
++    ldr r3, [r0], #4 
++    ldr r4, [r1], #4
++    teq r3, r4 
++    bne infinite_loop
++    
++    subs    r2, r2, #4 
++    beq stack_setup 
++    bne compare_next_byte
++                                            
++infinite_loop: 
++    b   infinite_loop   @ infinite loop
++
++norflash_boot:
++
+ 	ldr	r2, _armboot_start
+ 	ldr	r3, _bss_start
+ 	sub	r2, r3, r2		/* r2 <- size of armboot            */
+@@ -216,10 +352,22 @@
+ 	cmp	r0, r1
+ 	ble	clbss_l
+ 
++    ldr r1, =GPBDAT
++    ldr r2, [r1]
++    bic r2, r2, #(1<<5)  
++    str r2, [r1]
++ 
+ 	ldr	pc, _start_armboot
+ 
+ _start_armboot:	.word start_armboot
+ 
++#ifdef CONFIG_S3C24X0
++#define STACK_BASE 0x33f00000
++#define STACK_SIZE 0x10000
++    .align  2
++    DW_STACK_START: .word   STACK_BASE+STACK_SIZE-4
++#endif
++
+ 
+ /*
+  *************************************************************************
+diff -Nuar u-boot-2010.09/arch/arm/cpu/arm920t/u-boot.lds u-boot-2010.09-1-basic/arch/arm/cpu/arm920t/u-boot.lds
+--- u-boot-2010.09/arch/arm/cpu/arm920t/u-boot.lds	2010-09-29 05:20:55.000000000 +0800
++++ u-boot-2010.09-1-basic/arch/arm/cpu/arm920t/u-boot.lds	2015-11-16 13:12:09.988998722 +0800
+@@ -40,6 +40,8 @@
+ 	.text :
+ 	{
+ 		arch/arm/cpu/arm920t/start.o	(.text)
++        board/lingyun/fl2440/lowlevel_init.o    (.text)
++        board/lingyun/fl2440/nand_read.o    (.text)
+ 		*(.text)
+ 	}
+ 
+diff -Nuar u-boot-2010.09/arch/arm/include/asm/arch-s3c24x0/s3c24x0_cpu.h u-boot-2010.09-1-basic/arch/arm/include/asm/arch-s3c24x0/s3c24x0_cpu.h
+--- u-boot-2010.09/arch/arm/include/asm/arch-s3c24x0/s3c24x0_cpu.h	2010-09-29 05:20:55.000000000 +0800
++++ u-boot-2010.09-1-basic/arch/arm/include/asm/arch-s3c24x0/s3c24x0_cpu.h	2015-11-16 13:12:09.989998693 +0800
+@@ -20,7 +20,7 @@
+ 
+ #ifdef CONFIG_S3C2400
+ 	#include <asm/arch/s3c2400.h>
+-#elif defined CONFIG_S3C2410
++#elif defined(CONFIG_S3C2410) || defined(CONFIG_S3C2440)
+ 	#include <asm/arch/s3c2410.h>
+ #else
+ 	#error Please define the s3c24x0 cpu type
+diff -Nuar u-boot-2010.09/arch/arm/include/asm/arch-s3c24x0/s3c24x0.h u-boot-2010.09-1-basic/arch/arm/include/asm/arch-s3c24x0/s3c24x0.h
+--- u-boot-2010.09/arch/arm/include/asm/arch-s3c24x0/s3c24x0.h	2010-09-29 05:20:55.000000000 +0800
++++ u-boot-2010.09-1-basic/arch/arm/include/asm/arch-s3c24x0/s3c24x0.h	2015-11-16 13:12:09.989998693 +0800
+@@ -78,7 +78,7 @@
+ 	u32	PRIORITY;
+ 	u32	INTPND;
+ 	u32	INTOFFSET;
+-#ifdef CONFIG_S3C2410
++#if defined(CONFIG_S3C2410) || defined (CONFIG_S3C2440)
+ 	u32	SUBSRCPND;
+ 	u32	INTSUBMSK;
+ #endif
+@@ -88,11 +88,11 @@
+ /* DMAS (see manual chapter 8) */
+ struct s3c24x0_dma {
+ 	u32	DISRC;
+-#ifdef CONFIG_S3C2410
++#if defined(CONFIG_S3C2410) || defined (CONFIG_S3C2440)
+ 	u32	DISRCC;
+ #endif
+ 	u32	DIDST;
+-#ifdef CONFIG_S3C2410
++#if defined(CONFIG_S3C2410) || defined (CONFIG_S3C2440)
+ 	u32	DIDSTC;
+ #endif
+ 	u32	DCON;
+@@ -103,7 +103,7 @@
+ #ifdef CONFIG_S3C2400
+ 	u32	res[1];
+ #endif
+-#ifdef CONFIG_S3C2410
++#if defined(CONFIG_S3C2410) || defined (CONFIG_S3C2440)
+ 	u32	res[7];
+ #endif
+ };
+@@ -122,6 +122,9 @@
+ 	u32	CLKCON;
+ 	u32	CLKSLOW;
+ 	u32	CLKDIVN;
++#if defined (CONFIG_S3C2440) 
++    u32 CAMDIVN;
++#endif
+ };
+ 
+ 
+@@ -141,7 +144,7 @@
+ 	u32	res[8];
+ 	u32	DITHMODE;
+ 	u32	TPAL;
+-#ifdef CONFIG_S3C2410
++#if defined(CONFIG_S3C2410) || defined (CONFIG_S3C2440)
+ 	u32	LCDINTPND;
+ 	u32	LCDSRCPND;
+ 	u32	LCDINTMSK;
+@@ -151,6 +154,7 @@
+ 
+ 
+ /* NAND FLASH (see S3C2410 manual chapter 6) */
++#if defined(CONFIG_S3C2410)
+ struct s3c2410_nand {
+ 	u32	NFCONF;
+ 	u32	NFCMD;
+@@ -159,6 +163,26 @@
+ 	u32	NFSTAT;
+ 	u32	NFECC;
+ };
++#elif defined (CONFIG_S3C2440)
++struct s3c2410_nand { 
++    u32 NFCONF; 
++    u32 NFCONT; 
++    u32 NFCMD; 
++    u32 NFADDR; 
++    u32 NFDATA; 
++    u32 NFMECCD0; 
++    u32 NFMECCD1; 
++    u32 NFSECCD; 
++    u32 NFSTAT; 
++    u32 NFESTAT0; 
++    u32 NFESTAT1; 
++    u32 NFMECC0; 
++    u32 NFMECC1; 
++    u32 NFSECC; 
++    u32 NFSBLK; 
++    u32 NFEBLK;
++};
++#endif
+ 
+ 
+ /* UART (see manual chapter 11) */
+@@ -397,7 +421,7 @@
+ 	u32	MISCCR;
+ 	u32	EXTINT;
+ #endif
+-#ifdef CONFIG_S3C2410
++#if defined(CONFIG_S3C2410) || defined (CONFIG_S3C2440)
+ 	u32	GPACON;
+ 	u32	GPADAT;
+ 	u32	res1[2];
+@@ -446,6 +470,13 @@
+ 	u32	GSTATUS2;
+ 	u32	GSTATUS3;
+ 	u32	GSTATUS4;
++#if defined (CONFIG_S3C2440) 
++    u32 res9[3]; 
++    u32 MSLCON; 
++    u32 GPJCON; 
++    u32 GPJDAT; 
++    u32 GPJUP;
++#endif
+ #endif
+ };
+ 
+diff -Nuar u-boot-2010.09/board/lingyun/fl2440/config.mk u-boot-2010.09-1-basic/board/lingyun/fl2440/config.mk
+--- u-boot-2010.09/board/lingyun/fl2440/config.mk	1970-01-01 08:00:00.000000000 +0800
++++ u-boot-2010.09-1-basic/board/lingyun/fl2440/config.mk	2015-11-16 13:12:09.989998693 +0800
+@@ -0,0 +1,25 @@
++#
++# (C) Copyright 2002
++# Gary Jennejohn, DENX Software Engineering, <garyj@denx.de>
++# David Mueller, ELSOFT AG, <d.mueller@elsoft.ch>
++#
++# SAMSUNG SMDK2410 board with S3C2410X (ARM920T) cpu
++#
++# see http://www.samsung.com/ for more information on SAMSUNG
++#
++
++#
++# SMDK2410 has 1 bank of 64 MB DRAM
++#
++# 3000'0000 to 3400'0000
++#
++# Linux-Kernel is expected to be at 3000'8000, entry 3000'8000
++# optionally with a ramdisk at 3080'0000
++#
++# we load ourself to 33F8'0000
++#
++# download area is 3300'0000
++#
++
++
++TEXT_BASE = 0x33F80000
+diff -Nuar u-boot-2010.09/board/lingyun/fl2440/fl2440.c u-boot-2010.09-1-basic/board/lingyun/fl2440/fl2440.c
+--- u-boot-2010.09/board/lingyun/fl2440/fl2440.c	1970-01-01 08:00:00.000000000 +0800
++++ u-boot-2010.09-1-basic/board/lingyun/fl2440/fl2440.c	2015-11-16 13:15:03.314998179 +0800
+@@ -0,0 +1,171 @@
++/*
++ * (C) Copyright 2002
++ * Sysgo Real-Time Solutions, GmbH <www.elinos.com>
++ * Marius Groeger <mgroeger@sysgo.de>
++ *
++ * (C) Copyright 2002
++ * David Mueller, ELSOFT AG, <d.mueller@elsoft.ch>
++ *
++ * See file CREDITS for list of people who contributed to this
++ * project.
++ *
++ * This program is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU General Public License as
++ * published by the Free Software Foundation; either version 2 of
++ * the License, or (at your option) any later version.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
++ * MA 02111-1307 USA
++ */
++
++#include <common.h>
++#include <netdev.h>
++#include <asm/arch/s3c24x0_cpu.h>
++
++DECLARE_GLOBAL_DATA_PTR;
++
++#define FCLK_SPEED 1
++
++#if FCLK_SPEED==0		/* Fout = 203MHz, Fin = 12MHz for Audio */
++#define M_MDIV	0xC3
++#define M_PDIV	0x4
++#define M_SDIV	0x1
++#elif FCLK_SPEED==1     /* Fout = 405MHz, modify by guowenxue */
++#define M_MDIV 0x7f 
++#define M_PDIV 0x2
++#define M_SDIV 0x1
++#endif
++
++#define USB_CLOCK 1
++
++#if USB_CLOCK==0
++#define U_M_MDIV	0xA1
++#define U_M_PDIV	0x3
++#define U_M_SDIV	0x1
++#elif USB_CLOCK==1
++#define U_M_MDIV	0x38 /* Modify by guowenxue */
++#define U_M_PDIV	0x3
++#define U_M_SDIV	0x2
++#endif
++
++static inline void delay (unsigned long loops)
++{
++	__asm__ volatile ("1:\n"
++	  "subs %0, %1, #1\n"
++	  "bne 1b":"=r" (loops):"0" (loops));
++}
++
++#ifdef CONFIG_FL2440_BEEP /* Add by guowenxue, 2012.10.04 */
++#define BEEP         0    /* Buzzer use GPB0 */
++#define DELAY_TIME   10000000
++
++void turn_beep(void)
++{
++    int                  count = 2;
++    struct s3c24x0_gpio * const gpio = s3c24x0_get_base_gpio();
++
++    gpio->GPBCON = (gpio->GPBCON|0x3)&0x1; /*  Set GPB0 as GPIO output mode(0x01) */
++
++    while(count--)
++    {
++        gpio->GPBCON = (gpio->GPBCON|0x3)&0x1; /*  Set GPB0 as GPIO output mode(0x01) */
++
++        gpio->GPBDAT &= ~(1<<BEEP);  /*  Set Beep GPIO as low level */
++        delay(DELAY_TIME);
++
++        gpio->GPBDAT |= 1<<BEEP;     /*  Set Beep GPIO as high level */
++        delay(DELAY_TIME);
++
++        gpio->GPBCON &= ~0x3; /*  Set GPB0 as GPIO input mode(0x00) */
++    }
++
++    return ;
++}
++#endif
++
++/*
++ * Miscellaneous platform dependent initialisations
++ */
++
++int board_init (void)
++{
++	struct s3c24x0_clock_power * const clk_power =
++					s3c24x0_get_base_clock_power();
++	struct s3c24x0_gpio * const gpio = s3c24x0_get_base_gpio();
++
++	/* to reduce PLL lock time, adjust the LOCKTIME register */
++	clk_power->LOCKTIME = 0xFFFFFF;
++
++	/* configure MPLL */
++	clk_power->MPLLCON = ((M_MDIV << 12) + (M_PDIV << 4) + M_SDIV);
++
++	/* some delay between MPLL and UPLL */
++	delay (4000);
++
++	/* configure UPLL */
++	clk_power->UPLLCON = ((U_M_MDIV << 12) + (U_M_PDIV << 4) + U_M_SDIV);
++
++	/* some delay between MPLL and UPLL */
++	delay (8000);
++
++	/* set up the I/O ports */
++	gpio->GPACON = 0x007FFFFF;
++	gpio->GPBCON = 0x00044555;
++	gpio->GPBUP = 0x000007FF;
++	gpio->GPCCON = 0xAAAAAAAA;
++	gpio->GPCUP = 0x0000FFFF;
++	gpio->GPDCON = 0xAAAAAAAA;
++	gpio->GPDUP = 0x0000FFFF;
++	gpio->GPECON = 0xAAAAAAAA;
++	gpio->GPEUP = 0x0000FFFF;
++	gpio->GPFCON = 0x000055AA;
++	gpio->GPFUP = 0x000000FF;
++	gpio->GPGCON = 0xFF95FFBA;
++	gpio->GPGUP = 0x0000FFFF;
++	gpio->GPHCON = 0x002AFAAA;
++	gpio->GPHUP = 0x000007FF;
++
++	/* arch number of SMDK2410-Board */
++	gd->bd->bi_arch_number = MACH_TYPE_SMDK2410;
++
++	/* adress of boot parameters */
++	gd->bd->bi_boot_params = 0x30000100;
++
++	icache_enable();
++	dcache_enable();
++
++#if defined(CONFIG_FL2440_LED) /* Add by guowenxue, 2012.10.04 */
++    gpio->GPBDAT = 0x00000181;
++#endif
++#ifdef CONFIG_FL2440_BEEP /* Add by guowenxue, 2012.10.04 */
++    turn_beep();
++#endif
++
++	return 0;
++}
++
++int dram_init (void)
++{
++	gd->bd->bi_dram[0].start = PHYS_SDRAM_1;
++	gd->bd->bi_dram[0].size = PHYS_SDRAM_1_SIZE;
++
++	return 0;
++}
++
++#ifdef CONFIG_CMD_NET
++int board_eth_init(bd_t *bis)
++{
++	int rc = 0;
++#ifdef CONFIG_CS8900
++	rc = cs8900_initialize(0, CONFIG_CS8900_BASE);
++#endif
++	return rc;
++}
++#endif
+diff -Nuar u-boot-2010.09/board/lingyun/fl2440/flash.c u-boot-2010.09-1-basic/board/lingyun/fl2440/flash.c
+--- u-boot-2010.09/board/lingyun/fl2440/flash.c	1970-01-01 08:00:00.000000000 +0800
++++ u-boot-2010.09-1-basic/board/lingyun/fl2440/flash.c	2015-11-16 13:12:09.991998636 +0800
+@@ -0,0 +1,433 @@
++/*
++ * (C) Copyright 2002
++ * Sysgo Real-Time Solutions, GmbH <www.elinos.com>
++ * Alex Zuepke <azu@sysgo.de>
++ *
++ * See file CREDITS for list of people who contributed to this
++ * project.
++ *
++ * This program is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU General Public License as
++ * published by the Free Software Foundation; either version 2 of
++ * the License, or (at your option) any later version.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
++ * MA 02111-1307 USA
++ */
++
++#include <common.h>
++
++ulong myflush (void);
++
++
++#define FLASH_BANK_SIZE	PHYS_FLASH_SIZE
++#define MAIN_SECT_SIZE  0x10000	/* 64 KB */
++
++flash_info_t flash_info[CONFIG_SYS_MAX_FLASH_BANKS];
++
++
++#define CMD_READ_ARRAY		0x000000F0
++#define CMD_UNLOCK1		0x000000AA
++#define CMD_UNLOCK2		0x00000055
++#define CMD_ERASE_SETUP		0x00000080
++#define CMD_ERASE_CONFIRM	0x00000030
++#define CMD_PROGRAM		0x000000A0
++#define CMD_UNLOCK_BYPASS	0x00000020
++
++#define MEM_FLASH_ADDR1		(*(volatile u16 *)(CONFIG_SYS_FLASH_BASE + (0x00000555 << 1)))
++#define MEM_FLASH_ADDR2		(*(volatile u16 *)(CONFIG_SYS_FLASH_BASE + (0x000002AA << 1)))
++
++#define BIT_ERASE_DONE		0x00000080
++#define BIT_RDY_MASK		0x00000080
++#define BIT_PROGRAM_ERROR	0x00000020
++#define BIT_TIMEOUT		0x80000000	/* our flag */
++
++#define READY 1
++#define ERR   2
++#define TMO   4
++
++/*-----------------------------------------------------------------------
++ */
++
++ulong flash_init (void)
++{
++	int i, j;
++	ulong size = 0;
++
++	for (i = 0; i < CONFIG_SYS_MAX_FLASH_BANKS; i++) {
++		ulong flashbase = 0;
++
++		flash_info[i].flash_id =
++#if defined(CONFIG_AMD_LV400)
++			(AMD_MANUFACT & FLASH_VENDMASK) |
++			(AMD_ID_LV400B & FLASH_TYPEMASK);
++#elif defined(CONFIG_AMD_LV800)
++			(AMD_MANUFACT & FLASH_VENDMASK) |
++			(AMD_ID_LV800B & FLASH_TYPEMASK);
++#else
++#error "Unknown flash configured"
++#endif
++			flash_info[i].size = FLASH_BANK_SIZE;
++		flash_info[i].sector_count = CONFIG_SYS_MAX_FLASH_SECT;
++		memset (flash_info[i].protect, 0, CONFIG_SYS_MAX_FLASH_SECT);
++		if (i == 0)
++			flashbase = PHYS_FLASH_1;
++		else
++			panic ("configured too many flash banks!\n");
++		for (j = 0; j < flash_info[i].sector_count; j++) {
++			if (j <= 3) {
++				/* 1st one is 16 KB */
++				if (j == 0) {
++					flash_info[i].start[j] =
++						flashbase + 0;
++				}
++
++				/* 2nd and 3rd are both 8 KB */
++				if ((j == 1) || (j == 2)) {
++					flash_info[i].start[j] =
++						flashbase + 0x4000 + (j -
++								      1) *
++						0x2000;
++				}
++
++				/* 4th 32 KB */
++				if (j == 3) {
++					flash_info[i].start[j] =
++						flashbase + 0x8000;
++				}
++			} else {
++				flash_info[i].start[j] =
++					flashbase + (j - 3) * MAIN_SECT_SIZE;
++			}
++		}
++		size += flash_info[i].size;
++	}
++
++	flash_protect (FLAG_PROTECT_SET,
++		       CONFIG_SYS_FLASH_BASE,
++		       CONFIG_SYS_FLASH_BASE + monitor_flash_len - 1,
++		       &flash_info[0]);
++
++	flash_protect (FLAG_PROTECT_SET,
++		       CONFIG_ENV_ADDR,
++		       CONFIG_ENV_ADDR + CONFIG_ENV_SIZE - 1, &flash_info[0]);
++
++	return size;
++}
++
++/*-----------------------------------------------------------------------
++ */
++void flash_print_info (flash_info_t * info)
++{
++	int i;
++
++	switch (info->flash_id & FLASH_VENDMASK) {
++	case (AMD_MANUFACT & FLASH_VENDMASK):
++		printf ("AMD: ");
++		break;
++	default:
++		printf ("Unknown Vendor ");
++		break;
++	}
++
++	switch (info->flash_id & FLASH_TYPEMASK) {
++	case (AMD_ID_LV400B & FLASH_TYPEMASK):
++		printf ("1x Amd29LV400BB (4Mbit)\n");
++		break;
++	case (AMD_ID_LV800B & FLASH_TYPEMASK):
++		printf ("1x Amd29LV800BB (8Mbit)\n");
++		break;
++	default:
++		printf ("Unknown Chip Type\n");
++		goto Done;
++		break;
++	}
++
++	printf ("  Size: %ld MB in %d Sectors\n",
++		info->size >> 20, info->sector_count);
++
++	printf ("  Sector Start Addresses:");
++	for (i = 0; i < info->sector_count; i++) {
++		if ((i % 5) == 0) {
++			printf ("\n   ");
++		}
++		printf (" %08lX%s", info->start[i],
++			info->protect[i] ? " (RO)" : "     ");
++	}
++	printf ("\n");
++
++      Done:;
++}
++
++/*-----------------------------------------------------------------------
++ */
++
++int flash_erase (flash_info_t * info, int s_first, int s_last)
++{
++	ushort result;
++	int iflag, cflag, prot, sect;
++	int rc = ERR_OK;
++	int chip;
++
++	/* first look for protection bits */
++
++	if (info->flash_id == FLASH_UNKNOWN)
++		return ERR_UNKNOWN_FLASH_TYPE;
++
++	if ((s_first < 0) || (s_first > s_last)) {
++		return ERR_INVAL;
++	}
++
++	if ((info->flash_id & FLASH_VENDMASK) !=
++	    (AMD_MANUFACT & FLASH_VENDMASK)) {
++		return ERR_UNKNOWN_FLASH_VENDOR;
++	}
++
++	prot = 0;
++	for (sect = s_first; sect <= s_last; ++sect) {
++		if (info->protect[sect]) {
++			prot++;
++		}
++	}
++	if (prot)
++		return ERR_PROTECTED;
++
++	/*
++	 * Disable interrupts which might cause a timeout
++	 * here. Remember that our exception vectors are
++	 * at address 0 in the flash, and we don't want a
++	 * (ticker) exception to happen while the flash
++	 * chip is in programming mode.
++	 */
++	cflag = icache_status ();
++	icache_disable ();
++	iflag = disable_interrupts ();
++
++	/* Start erase on unprotected sectors */
++	for (sect = s_first; sect <= s_last && !ctrlc (); sect++) {
++		printf ("Erasing sector %2d ... ", sect);
++
++		/* arm simple, non interrupt dependent timer */
++		reset_timer_masked ();
++
++		if (info->protect[sect] == 0) {	/* not protected */
++			vu_short *addr = (vu_short *) (info->start[sect]);
++
++			MEM_FLASH_ADDR1 = CMD_UNLOCK1;
++			MEM_FLASH_ADDR2 = CMD_UNLOCK2;
++			MEM_FLASH_ADDR1 = CMD_ERASE_SETUP;
++
++			MEM_FLASH_ADDR1 = CMD_UNLOCK1;
++			MEM_FLASH_ADDR2 = CMD_UNLOCK2;
++			*addr = CMD_ERASE_CONFIRM;
++
++			/* wait until flash is ready */
++			chip = 0;
++
++			do {
++				result = *addr;
++
++				/* check timeout */
++				if (get_timer_masked () >
++				    CONFIG_SYS_FLASH_ERASE_TOUT) {
++					MEM_FLASH_ADDR1 = CMD_READ_ARRAY;
++					chip = TMO;
++					break;
++				}
++
++				if (!chip
++				    && (result & 0xFFFF) & BIT_ERASE_DONE)
++					chip = READY;
++
++				if (!chip
++				    && (result & 0xFFFF) & BIT_PROGRAM_ERROR)
++					chip = ERR;
++
++			} while (!chip);
++
++			MEM_FLASH_ADDR1 = CMD_READ_ARRAY;
++
++			if (chip == ERR) {
++				rc = ERR_PROG_ERROR;
++				goto outahere;
++			}
++			if (chip == TMO) {
++				rc = ERR_TIMOUT;
++				goto outahere;
++			}
++
++			printf ("ok.\n");
++		} else {	/* it was protected */
++
++			printf ("protected!\n");
++		}
++	}
++
++	if (ctrlc ())
++		printf ("User Interrupt!\n");
++
++      outahere:
++	/* allow flash to settle - wait 10 ms */
++	udelay_masked (10000);
++
++	if (iflag)
++		enable_interrupts ();
++
++	if (cflag)
++		icache_enable ();
++
++	return rc;
++}
++
++/*-----------------------------------------------------------------------
++ * Copy memory to flash
++ */
++
++static int write_hword (flash_info_t * info, ulong dest, ushort data)
++{
++	vu_short *addr = (vu_short *) dest;
++	ushort result;
++	int rc = ERR_OK;
++	int cflag, iflag;
++	int chip;
++
++	/*
++	 * Check if Flash is (sufficiently) erased
++	 */
++	result = *addr;
++	if ((result & data) != data)
++		return ERR_NOT_ERASED;
++
++
++	/*
++	 * Disable interrupts which might cause a timeout
++	 * here. Remember that our exception vectors are
++	 * at address 0 in the flash, and we don't want a
++	 * (ticker) exception to happen while the flash
++	 * chip is in programming mode.
++	 */
++	cflag = icache_status ();
++	icache_disable ();
++	iflag = disable_interrupts ();
++
++	MEM_FLASH_ADDR1 = CMD_UNLOCK1;
++	MEM_FLASH_ADDR2 = CMD_UNLOCK2;
++	MEM_FLASH_ADDR1 = CMD_UNLOCK_BYPASS;
++	*addr = CMD_PROGRAM;
++	*addr = data;
++
++	/* arm simple, non interrupt dependent timer */
++	reset_timer_masked ();
++
++	/* wait until flash is ready */
++	chip = 0;
++	do {
++		result = *addr;
++
++		/* check timeout */
++		if (get_timer_masked () > CONFIG_SYS_FLASH_ERASE_TOUT) {
++			chip = ERR | TMO;
++			break;
++		}
++		if (!chip && ((result & 0x80) == (data & 0x80)))
++			chip = READY;
++
++		if (!chip && ((result & 0xFFFF) & BIT_PROGRAM_ERROR)) {
++			result = *addr;
++
++			if ((result & 0x80) == (data & 0x80))
++				chip = READY;
++			else
++				chip = ERR;
++		}
++
++	} while (!chip);
++
++	*addr = CMD_READ_ARRAY;
++
++	if (chip == ERR || *addr != data)
++		rc = ERR_PROG_ERROR;
++
++	if (iflag)
++		enable_interrupts ();
++
++	if (cflag)
++		icache_enable ();
++
++	return rc;
++}
++
++/*-----------------------------------------------------------------------
++ * Copy memory to flash.
++ */
++
++int write_buff (flash_info_t * info, uchar * src, ulong addr, ulong cnt)
++{
++	ulong cp, wp;
++	int l;
++	int i, rc;
++	ushort data;
++
++	wp = (addr & ~1);	/* get lower word aligned address */
++
++	/*
++	 * handle unaligned start bytes
++	 */
++	if ((l = addr - wp) != 0) {
++		data = 0;
++		for (i = 0, cp = wp; i < l; ++i, ++cp) {
++			data = (data >> 8) | (*(uchar *) cp << 8);
++		}
++		for (; i < 2 && cnt > 0; ++i) {
++			data = (data >> 8) | (*src++ << 8);
++			--cnt;
++			++cp;
++		}
++		for (; cnt == 0 && i < 2; ++i, ++cp) {
++			data = (data >> 8) | (*(uchar *) cp << 8);
++		}
++
++		if ((rc = write_hword (info, wp, data)) != 0) {
++			return (rc);
++		}
++		wp += 2;
++	}
++
++	/*
++	 * handle word aligned part
++	 */
++	while (cnt >= 2) {
++		data = *((vu_short *) src);
++		if ((rc = write_hword (info, wp, data)) != 0) {
++			return (rc);
++		}
++		src += 2;
++		wp += 2;
++		cnt -= 2;
++	}
++
++	if (cnt == 0) {
++		return ERR_OK;
++	}
++
++	/*
++	 * handle unaligned tail bytes
++	 */
++	data = 0;
++	for (i = 0, cp = wp; i < 2 && cnt > 0; ++i, ++cp) {
++		data = (data >> 8) | (*src++ << 8);
++		--cnt;
++	}
++	for (; i < 2; ++i, ++cp) {
++		data = (data >> 8) | (*(uchar *) cp << 8);
++	}
++
++	return write_hword (info, wp, data);
++}
+diff -Nuar u-boot-2010.09/board/lingyun/fl2440/lowlevel_init.S u-boot-2010.09-1-basic/board/lingyun/fl2440/lowlevel_init.S
+--- u-boot-2010.09/board/lingyun/fl2440/lowlevel_init.S	1970-01-01 08:00:00.000000000 +0800
++++ u-boot-2010.09-1-basic/board/lingyun/fl2440/lowlevel_init.S	2015-11-16 13:12:09.991998636 +0800
+@@ -0,0 +1,198 @@
++/*
++ * Memory Setup stuff - taken from blob memsetup.S
++ *
++ * Copyright (C) 1999 2000 2001 Erik Mouw (J.A.K.Mouw@its.tudelft.nl) and
++ *                     Jan-Derk Bakker (J.D.Bakker@its.tudelft.nl)
++ *
++ * Modified for the Samsung SMDK2410 by
++ * (C) Copyright 2002
++ * David Mueller, ELSOFT AG, <d.mueller@elsoft.ch>
++ *
++ * See file CREDITS for list of people who contributed to this
++ * project.
++ *
++ * This program is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU General Public License as
++ * published by the Free Software Foundation; either version 2 of
++ * the License, or (at your option) any later version.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
++ * MA 02111-1307 USA
++ */
++
++
++#include <config.h>
++#include <version.h>
++
++
++/* some parameters for the board */
++
++/*
++ *
++ * Taken from linux/arch/arm/boot/compressed/head-s3c2410.S
++ *
++ * Copyright (C) 2002 Samsung Electronics SW.LEE  <hitchcar@sec.samsung.com>
++ *
++ */
++
++#define BWSCON	0x48000000
++#define GPBCON                      0x56000010
++#define GPBDAT                      0x56000014
++#define GPBUP                       0x56000018
++
++/* BWSCON */
++#define DW8			(0x0)
++#define DW16			(0x1)
++#define DW32			(0x2)
++#define WAIT			(0x1<<2)
++#define UBLB			(0x1<<3)
++
++#define B1_BWSCON		(DW32)
++#define B2_BWSCON		(DW16)
++#define B3_BWSCON		(DW16 + WAIT + UBLB)
++#define B4_BWSCON		(DW16)
++#define B5_BWSCON		(DW16)
++#define B6_BWSCON		(DW32)
++#define B7_BWSCON		(DW32)
++
++/* BANK0CON */
++#define B0_Tacs			0x0	/*  0clk */
++#define B0_Tcos			0x0	/*  0clk */
++#define B0_Tacc			0x7	/* 14clk */
++#define B0_Tcoh			0x0	/*  0clk */
++#define B0_Tah			0x0	/*  0clk */
++#define B0_Tacp			0x0
++#define B0_PMC			0x0	/* normal */
++
++/* BANK1CON */
++#define B1_Tacs			0x0	/*  0clk */
++#define B1_Tcos			0x0	/*  0clk */
++#define B1_Tacc			0x7	/* 14clk */
++#define B1_Tcoh			0x0	/*  0clk */
++#define B1_Tah			0x0	/*  0clk */
++#define B1_Tacp			0x0
++#define B1_PMC			0x0
++
++#define B2_Tacs			0x0
++#define B2_Tcos			0x0
++#define B2_Tacc			0x7
++#define B2_Tcoh			0x0
++#define B2_Tah			0x0
++#define B2_Tacp			0x0
++#define B2_PMC			0x0
++
++#define B3_Tacs			0x0	/*  0clk */
++#define B3_Tcos			0x3	/*  4clk */
++#define B3_Tacc			0x7	/* 14clk */
++#define B3_Tcoh			0x1	/*  1clk */
++#define B3_Tah			0x0	/*  0clk */
++#define B3_Tacp			0x3     /*  6clk */
++#define B3_PMC			0x0	/* normal */
++
++#define B4_Tacs			0x0	/*  0clk */
++#define B4_Tcos			0x0	/*  0clk */
++#define B4_Tacc			0x7	/* 14clk */
++#define B4_Tcoh			0x0	/*  0clk */
++#define B4_Tah			0x0	/*  0clk */
++#define B4_Tacp			0x0
++#define B4_PMC			0x0	/* normal */
++
++#define B5_Tacs			0x0	/*  0clk */
++#define B5_Tcos			0x0	/*  0clk */
++#define B5_Tacc			0x7	/* 14clk */
++#define B5_Tcoh			0x0	/*  0clk */
++#define B5_Tah			0x0	/*  0clk */
++#define B5_Tacp			0x0
++#define B5_PMC			0x0	/* normal */
++
++/* SDRAM is on HSB bus, so its clock is from HCLK, FCLK=400, HCLK=100; so SDRAM 1clk=10ns */
++
++#define B6_MT           0x3 /*  SDRAM */
++// K4S561632 datasheet: RAS to CAS delay(Trcd) Min value should be 18/20ns, HCLK is 100MHz, so 1clk=10ns
++// EM63A165  datasheet: RAS# to CAS# delay(Trcd) Min value should be 15/20ns, HCLK is 100MHz, so 1clk=10ns
++#define B6_Trcd         0x2 /* 4clk */
++#define B6_SCAN         0x1 /* 9bit */
++
++#define B7_MT			0x3	/* SDRAM */
++#define B7_Trcd			0x1	/* 3clk */
++#define B7_SCAN			0x1	/* 9bit */
++
++/* REFRESH register<0x48000024> parameter */
++#define REFEN           0x1 /*  Refresh enable */
++#define TREFMD          0x0 /*  CBR(CAS before RAS)/Auto refresh */
++
++//                 Trp: Row precharge time
++// K4S561632 datasheet: Min(Trp) value should be 18/20ns;
++// EM63A165 datasheet:  Min value should be 15/20ns;
++#define Trp             0x2 /*  4clk */
++
++//                Trc:  Row cycle time
++// K4S561632 datasheet: Min value should be 60/65ns;
++// EM63A165 datasheet:  Min value should be 60/63ns;
++// S3C2440  datasheet:  REFRESH register describe: SDRAM Row cycle time: Trc=Tsrc+Trp
++#define Tsrc            0x2 /* 6clk, so Trc=Tsrc+Trp=6+3=9clk */
++
++// K4S561632 datasheet: 64ms refresh period (8K Cycle):  64000/8192=7.81us
++// EM63A165  datasheet: 8192 refresh cycles/64ms:        64000/8192=7.81us
++// S3C2440   datasheet: REFRESH Register Refresh period = (2^11-refresh_count+1)/HCLK
++//                      So Refresh count = 2^11 + 1 - 100x7.81 = 1268
++#define REFCNT          1268
++//#define REFCNT          489 /* HCLK=100Mhz, (2048+1-15.6*100) */
++
++
++/**************************************/
++
++_TEXT_BASE:
++	.word	TEXT_BASE
++
++.globl lowlevel_init
++lowlevel_init:
++    ldr r5, =GPBDAT
++    ldr r6, [r5]
++    bic r6, r6, #(1<<8)  
++    str r6, [r5]
++
++	/* memory control configuration */
++	/* make r0 relative the current location so that it */
++	/* reads SMRDATA out of FLASH rather than memory ! */
++	ldr     r0, =SMRDATA
++	ldr	    r1, =lowlevel_init
++	sub	    r0, r0, r1
++    adr     r3, lowlevel_init /* r3 <- current position of code */
++    add     r0, r0, r3
++	ldr	    r1, =BWSCON	/* Bus Width Status Controller */
++	add     r2, r0, #13*4
++
++0:
++	ldr     r3, [r0], #4
++	str     r3, [r1], #4
++	cmp     r2, r0
++	bne     0b
++
++	/* everything is fine now */
++	mov	pc, lr
++
++	.ltorg
++/* the literal pools origin */
++
++SMRDATA:
++    .word (0+(B1_BWSCON<<4)+(B2_BWSCON<<8)+(B3_BWSCON<<12)+(B4_BWSCON<<16)+(B5_BWSCON<<20)+(B6_BWSCON<<24)+(B7_BWSCON<<28))
++    .word ((B0_Tacs<<13)+(B0_Tcos<<11)+(B0_Tacc<<8)+(B0_Tcoh<<6)+(B0_Tah<<4)+(B0_Tacp<<2)+(B0_PMC))
++    .word ((B1_Tacs<<13)+(B1_Tcos<<11)+(B1_Tacc<<8)+(B1_Tcoh<<6)+(B1_Tah<<4)+(B1_Tacp<<2)+(B1_PMC))
++    .word ((B2_Tacs<<13)+(B2_Tcos<<11)+(B2_Tacc<<8)+(B2_Tcoh<<6)+(B2_Tah<<4)+(B2_Tacp<<2)+(B2_PMC))
++    .word ((B3_Tacs<<13)+(B3_Tcos<<11)+(B3_Tacc<<8)+(B3_Tcoh<<6)+(B3_Tah<<4)+(B3_Tacp<<2)+(B3_PMC))
++    .word ((B4_Tacs<<13)+(B4_Tcos<<11)+(B4_Tacc<<8)+(B4_Tcoh<<6)+(B4_Tah<<4)+(B4_Tacp<<2)+(B4_PMC))
++    .word ((B5_Tacs<<13)+(B5_Tcos<<11)+(B5_Tacc<<8)+(B5_Tcoh<<6)+(B5_Tah<<4)+(B5_Tacp<<2)+(B5_PMC))
++    .word ((B6_MT<<15)+(B6_Trcd<<2)+(B6_SCAN))
++    .word ((B7_MT<<15)+(B7_Trcd<<2)+(B7_SCAN))
++    .word ((REFEN<<23)+(TREFMD<<22)+(Trp<<20)+(Tsrc<<18)+REFCNT)
++    .word 0xb2
++    .word 0x30
++    .word 0x30
+diff -Nuar u-boot-2010.09/board/lingyun/fl2440/Makefile u-boot-2010.09-1-basic/board/lingyun/fl2440/Makefile
+--- u-boot-2010.09/board/lingyun/fl2440/Makefile	1970-01-01 08:00:00.000000000 +0800
++++ u-boot-2010.09-1-basic/board/lingyun/fl2440/Makefile	2015-11-16 13:12:09.991998636 +0800
+@@ -0,0 +1,51 @@
++#
++# (C) Copyright 2000-2006
++# Wolfgang Denk, DENX Software Engineering, wd@denx.de.
++#
++# See file CREDITS for list of people who contributed to this
++# project.
++#
++# This program is free software; you can redistribute it and/or
++# modify it under the terms of the GNU General Public License as
++# published by the Free Software Foundation; either version 2 of
++# the License, or (at your option) any later version.
++#
++# This program is distributed in the hope that it will be useful,
++# but WITHOUT ANY WARRANTY; without even the implied warranty of
++# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++# GNU General Public License for more details.
++#
++# You should have received a copy of the GNU General Public License
++# along with this program; if not, write to the Free Software
++# Foundation, Inc., 59 Temple Place, Suite 330, Boston,
++# MA 02111-1307 USA
++#
++
++include $(TOPDIR)/config.mk
++
++LIB	= $(obj)lib$(BOARD).a
++
++COBJS	:= fl2440.o nand_read.o flash.o
++SOBJS	:= lowlevel_init.o
++
++SRCS	:= $(SOBJS:.o=.S) $(COBJS:.o=.c)
++OBJS	:= $(addprefix $(obj),$(COBJS))
++SOBJS	:= $(addprefix $(obj),$(SOBJS))
++
++$(LIB):	$(obj).depend $(OBJS) $(SOBJS)
++	$(AR) $(ARFLAGS) $@ $(OBJS) $(SOBJS)
++
++clean:
++	rm -f $(SOBJS) $(OBJS)
++
++distclean:	clean
++	rm -f $(LIB) core *.bak $(obj).depend
++
++#########################################################################
++
++# defines $(obj).depend target
++include $(SRCTREE)/rules.mk
++
++sinclude $(obj).depend
++
++#########################################################################
+diff -Nuar u-boot-2010.09/board/lingyun/fl2440/nand_read.c u-boot-2010.09-1-basic/board/lingyun/fl2440/nand_read.c
+--- u-boot-2010.09/board/lingyun/fl2440/nand_read.c	1970-01-01 08:00:00.000000000 +0800
++++ u-boot-2010.09-1-basic/board/lingyun/fl2440/nand_read.c	2015-11-16 13:12:09.991998636 +0800
+@@ -0,0 +1,212 @@
++/*
++ * nand_read.c: Simple NAND read functions for booting from NAND
++ *
++ * This is used by cpu/arm920/start.S assembler code,
++ * and the board-specific linker script must make sure this
++ * file is linked within the first 4kB of NAND flash.
++ *
++ * Taken from GPLv2 licensed vivi bootloader,
++ * Copyright (C) 2002 MIZI Research, Inc.
++ *
++ * Author: Hwang, Chideok <hwang@mizi.com>
++ * Date  : $Date: 2004/02/04 10:37:37 $
++ *
++ * u-boot integration and bad-block skipping (C) 2006 by OpenMoko, Inc.
++ * Author: Harald Welte <laforge@openmoko.org>
++ */
++
++#include <common.h>
++#include <linux/mtd/nand.h>
++
++
++#define __REGb(x)	(*(volatile unsigned char *)(x))
++#define __REGw(x)	(*(volatile unsigned short *)(x))
++#define __REGi(x)	(*(volatile unsigned int *)(x))
++#define NF_BASE		0x4e000000
++#if defined(CONFIG_S3C2410)
++#define NFCONF		__REGi(NF_BASE + 0x0)
++#define NFCMD		__REGb(NF_BASE + 0x4)
++#define NFADDR		__REGb(NF_BASE + 0x8)
++#define NFDATA		__REGb(NF_BASE + 0xc)
++#define NFSTAT		__REGb(NF_BASE + 0x10)
++#define NFSTAT_BUSY	1
++#define nand_select()	(NFCONF &= ~0x800)
++#define nand_deselect()	(NFCONF |= 0x800)
++#define nand_clear_RnB()	do {} while (0)
++#elif defined(CONFIG_S3C2440) || defined(CONFIG_S3C2442)
++#define NFCONF		__REGi(NF_BASE + 0x0)
++#define NFCONT		__REGi(NF_BASE + 0x4)
++#define NFCMD		__REGb(NF_BASE + 0x8)
++#define NFADDR		__REGb(NF_BASE + 0xc)
++#define NFDATA		__REGb(NF_BASE + 0x10)
++#define NFDATA16	__REGw(NF_BASE + 0x10)
++#define NFSTAT		__REGb(NF_BASE + 0x20)
++#define NFSTAT_BUSY	1
++#define nand_select()	(NFCONT &= ~(1 << 1))
++#define nand_deselect()	(NFCONT |= (1 << 1))
++#define nand_clear_RnB()	(NFSTAT |= (1 << 2))
++#endif
++
++static inline void nand_wait(void)
++{
++	int i;
++
++	while (!(NFSTAT & NFSTAT_BUSY))
++		for (i=0; i<10; i++);
++}
++
++struct boot_nand_t {
++	int page_size;
++	int block_size;
++	int bad_block_offset;
++};
++
++static int is_bad_block(struct boot_nand_t * nand, unsigned long i)
++{
++	unsigned char data;
++	unsigned long page_num;
++
++	nand_clear_RnB();
++	if (nand->page_size == 512) {
++		NFCMD = NAND_CMD_READOOB; /* 0x50 */
++		NFADDR = nand->bad_block_offset & 0xf;
++		NFADDR = (i >> 9) & 0xff;
++		NFADDR = (i >> 17) & 0xff;
++		NFADDR = (i >> 25) & 0xff;
++	} else if (nand->page_size == 2048) {
++		page_num = i >> 11; /* addr / 2048 */
++		NFCMD = NAND_CMD_READ0;
++		NFADDR = nand->bad_block_offset & 0xff;
++		NFADDR = (nand->bad_block_offset >> 8) & 0xff;
++		NFADDR = page_num & 0xff;
++		NFADDR = (page_num >> 8) & 0xff;
++		NFADDR = (page_num >> 16) & 0xff;
++		NFCMD = NAND_CMD_READSTART;
++	} else {
++		return -1;
++	}
++	nand_wait();
++	data = (NFDATA & 0xff);
++	if (data != 0xff)
++		return 1;
++
++	return 0;
++}
++
++static int nand_read_page_ll(struct boot_nand_t * nand, unsigned char *buf, unsigned long addr)
++{
++	unsigned short *ptr16 = (unsigned short *)buf;
++	unsigned int i, page_num;
++
++	nand_clear_RnB();
++
++	NFCMD = NAND_CMD_READ0;
++
++	if (nand->page_size == 512) {
++		/* Write Address */
++		NFADDR = addr & 0xff;
++		NFADDR = (addr >> 9) & 0xff;
++		NFADDR = (addr >> 17) & 0xff;
++		NFADDR = (addr >> 25) & 0xff;
++	} else if (nand->page_size == 2048) {
++		page_num = addr >> 11; /* addr / 2048 */
++		/* Write Address */
++		NFADDR = 0;
++		NFADDR = 0;
++		NFADDR = page_num & 0xff;
++		NFADDR = (page_num >> 8) & 0xff;
++		NFADDR = (page_num >> 16) & 0xff;
++		NFCMD = NAND_CMD_READSTART;
++	} else {
++		return -1;
++	}
++	nand_wait();
++
++#if defined(CONFIG_S3C2410)
++	for (i = 0; i < nand->page_size; i++) {
++		*buf = (NFDATA & 0xff);
++		buf++;
++	}
++#elif defined(CONFIG_S3C2440) || defined(CONFIG_S3C2442)
++	for (i = 0; i < (nand->page_size>>1); i++) {
++		*ptr16 = NFDATA16;
++		ptr16++;
++	}
++#endif
++
++	return nand->page_size;
++}
++
++static unsigned short nand_read_id()
++{
++	unsigned short res = 0;
++	NFCMD = NAND_CMD_READID;
++	NFADDR = 0;
++	res = NFDATA;
++	res = (res << 8) | NFDATA;
++	return res;
++}
++
++extern unsigned int dynpart_size[];
++
++/* low level nand read function */
++int nand_read_ll(unsigned char *buf, unsigned long start_addr, int size)
++{
++	int i, j;
++	unsigned short nand_id;
++	struct boot_nand_t nand;
++
++	/* chip Enable */
++	nand_select();
++	nand_clear_RnB();
++	
++	for (i = 0; i < 10; i++)
++		;
++	nand_id = nand_read_id();
++	if (0) { /* dirty little hack to detect if nand id is misread */
++		unsigned short * nid = (unsigned short *)0x31fffff0;
++		*nid = nand_id;
++	}	
++
++       if (nand_id == 0xec76 ||		/* Samsung K91208 on SD2410 board */
++           nand_id == 0xad76 ) {	/*Hynix HY27US08121A*/
++		nand.page_size = 512;
++		nand.block_size = 16 * 1024;
++		nand.bad_block_offset = 5;
++	//	nand.size = 0x4000000;
++	} else if (nand_id == 0xecf1 ||	/* Samsung K9F1G08U0B */
++           nand_id == 0xadda || /*  Hynix HY27UF082G2B on FL2440 board */
++		   nand_id == 0xecda ||	/* Samsung K9F2G08U0B on FL2440 board */
++		   nand_id == 0xecd3 )	{ /* Samsung K9K8G08 */
++		nand.page_size = 2048;
++		nand.block_size = 128 * 1024;
++		nand.bad_block_offset = nand.page_size;
++	//	nand.size = 0x8000000;
++	} else {
++		return -1; // hang
++	}
++	if ((start_addr & (nand.block_size-1)) || (size & ((nand.block_size-1))))
++		return -1;	/* invalid alignment */
++
++	for (i=start_addr; i < (start_addr + size);) {
++#ifdef CONFIG_S3C2410_NAND_SKIP_BAD
++		if (i & (nand.block_size-1)== 0) {
++			if (is_bad_block(&nand, i) ||
++			    is_bad_block(&nand, i + nand.page_size)) {
++				/* Bad block */
++				i += nand.block_size;
++				size += nand.block_size;
++				continue;
++			}
++		}
++#endif
++		j = nand_read_page_ll(&nand, buf, i);
++		i += j;
++		buf += j;
++	}
++
++	/* chip Disable */
++	nand_deselect();
++
++	return 0;
++}
+diff -Nuar u-boot-2010.09/boards.cfg u-boot-2010.09-1-basic/boards.cfg
+--- u-boot-2010.09/boards.cfg	2010-09-29 05:20:55.000000000 +0800
++++ u-boot-2010.09-1-basic/boards.cfg	2015-11-16 13:12:09.991998636 +0800
+@@ -238,6 +238,7 @@
+ sbc2410x	arm	arm920t		-		-		s3c24x0
+ smdk2400	arm	arm920t		-		samsung		s3c24x0
+ smdk2410	arm	arm920t		-		samsung		s3c24x0
++fl2440  	arm	arm920t		fl2440	lingyun		s3c24x0
+ voiceblue	arm	arm925t
+ omap1510inn	arm	arm925t		-		ti
+ afeb9260	arm	arm926ejs	-		-		at91
+diff -Nuar u-boot-2010.09/common/serial.c u-boot-2010.09-1-basic/common/serial.c
+--- u-boot-2010.09/common/serial.c	2010-09-29 05:20:55.000000000 +0800
++++ u-boot-2010.09-1-basic/common/serial.c	2015-11-16 13:12:09.991998636 +0800
+@@ -68,7 +68,7 @@
+ #else
+ #error "Bad CONFIG_PSC_CONSOLE."
+ #endif
+-#elif defined(CONFIG_S3C2410)
++#elif defined(CONFIG_S3C2410) || defined(CONFIG_S3C2440)
+ #if defined(CONFIG_SERIAL1)
+ 	return &s3c24xx_serial0_device;
+ #elif defined(CONFIG_SERIAL2)
+@@ -157,7 +157,7 @@
+ #if defined (CONFIG_STUART)
+ 	serial_register(&serial_stuart_device);
+ #endif
+-#if defined(CONFIG_S3C2410)
++#if defined(CONFIG_S3C2410) || defined(CONFIG_S3C2440)
+ 	serial_register(&s3c24xx_serial0_device);
+ 	serial_register(&s3c24xx_serial1_device);
+ 	serial_register(&s3c24xx_serial2_device);
+diff -Nuar u-boot-2010.09/include/configs/fl2440.h u-boot-2010.09-1-basic/include/configs/fl2440.h
+--- u-boot-2010.09/include/configs/fl2440.h	1970-01-01 08:00:00.000000000 +0800
++++ u-boot-2010.09-1-basic/include/configs/fl2440.h	2015-11-16 13:15:25.644998137 +0800
+@@ -0,0 +1,187 @@
++/*
++ * (C) Copyright 2002
++ * Sysgo Real-Time Solutions, GmbH <www.elinos.com>
++ * Marius Groeger <mgroeger@sysgo.de>
++ * Gary Jennejohn <garyj@denx.de>
++ * David Mueller <d.mueller@elsoft.ch>
++ *
++ * Configuation settings for the SAMSUNG SMDK2410 board.
++ *
++ * See file CREDITS for list of people who contributed to this
++ * project.
++ *
++ * This program is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU General Public License as
++ * published by the Free Software Foundation; either version 2 of
++ * the License, or (at your option) any later version.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
++ * MA 02111-1307 USA
++ */
++
++#ifndef __CONFIG_H
++#define __CONFIG_H
++
++/*
++ * High Level Configuration Options
++ * (easy to change)
++ */
++#define CONFIG_ARM920T	1	/* This is an ARM920T Core	*/
++#define CONFIG_S3C24X0	1	/* in a SAMSUNG S3C24x0-type SoC	*/
++#define CONFIG_S3C2440  1   /*  specifically a SAMSUNG S3C2440 SoC   */ 
++#define CONFIG_FL2440   1   /*  FL2440 board */ 
++
++#define CONFIG_FL2440_LED               1
++#define CONFIG_FL2440_BEEP              1
++#define CONFIG_S3C2410_NAND_SKIP_BAD    1
++
++/* input clock of PLL */
++#define CONFIG_SYS_CLK_FREQ	12000000/* the SMDK2410 has 12MHz input clock */
++
++
++#define USE_920T_MMU		1
++#undef CONFIG_USE_IRQ			/* we don't need IRQ/FIQ stuff */
++
++/*
++ * Size of malloc() pool
++ */
++#define CONFIG_SYS_MALLOC_LEN		(CONFIG_ENV_SIZE + 128*1024)
++#define CONFIG_SYS_GBL_DATA_SIZE	128	/* size in bytes reserved for initial data */
++
++/*
++ * Hardware drivers
++ */
++#define CONFIG_NET_MULTI
++#define CONFIG_CS8900		/* we have a CS8900 on-board */
++#define CONFIG_CS8900_BASE	0x19000300
++#define CONFIG_CS8900_BUS16	/* the Linux driver does accesses as shorts */
++
++/*
++ * select serial console configuration
++ */
++#define CONFIG_S3C24X0_SERIAL
++#define CONFIG_SERIAL1          1	/* we use SERIAL 1 on SMDK2410 */
++
++/************************************************************
++ * RTC
++ ************************************************************/
++#define	CONFIG_RTC_S3C24X0	1
++
++/* allow to overwrite serial and ethaddr */
++#define CONFIG_ENV_OVERWRITE
++
++#define CONFIG_BAUDRATE		115200
++
++
++/*
++ * BOOTP options
++ */
++#define CONFIG_BOOTP_BOOTFILESIZE
++#define CONFIG_BOOTP_BOOTPATH
++#define CONFIG_BOOTP_GATEWAY
++#define CONFIG_BOOTP_HOSTNAME
++
++
++/*
++ * Command line configuration.
++ */
++#include <config_cmd_default.h>
++
++#define CONFIG_CMD_CACHE
++#define CONFIG_CMD_DATE
++#define CONFIG_CMD_ELF
++
++
++#define CONFIG_BOOTDELAY	2
++/*#define CONFIG_BOOTARGS	"root=ramfs devfs=mount console=ttySA0,9600" */
++/*#define CONFIG_ETHADDR	08:00:3e:26:0a:5b */
++#define CONFIG_NETMASK          255.255.255.0
++#define CONFIG_IPADDR		10.0.0.110
++#define CONFIG_SERVERIP		10.0.0.1
++/*#define CONFIG_BOOTFILE	"elinos-lart" */
++/*#define CONFIG_BOOTCOMMAND	"tftp; bootm" */
++
++#if defined(CONFIG_CMD_KGDB)
++#define CONFIG_KGDB_BAUDRATE	115200		/* speed to run kgdb serial port */
++/* what's this ? it's not used anywhere */
++#define CONFIG_KGDB_SER_INDEX	1		/* which serial port to use */
++#endif
++
++/*
++ * Miscellaneous configurable options
++ */
++#define	CONFIG_SYS_LONGHELP				/* undef to save memory		*/
++#define	CONFIG_SYS_PROMPT		"[fl2440@lingyun]# "	/* Monitor Command Prompt	*/
++#define	CONFIG_SYS_CBSIZE		256		/* Console I/O Buffer Size	*/
++#define	CONFIG_SYS_PBSIZE (CONFIG_SYS_CBSIZE+sizeof(CONFIG_SYS_PROMPT)+16) /* Print Buffer Size */
++#define	CONFIG_SYS_MAXARGS		16		/* max number of command args	*/
++#define CONFIG_SYS_BARGSIZE		CONFIG_SYS_CBSIZE	/* Boot Argument Buffer Size	*/
++
++#define CONFIG_SYS_MEMTEST_START	0x30000000	/* memtest works on	*/
++#define CONFIG_SYS_MEMTEST_END		0x33F00000	/* 63 MB in DRAM	*/
++
++#define	CONFIG_SYS_LOAD_ADDR		0x33000000	/* default load address	*/
++
++#define	CONFIG_SYS_HZ			1000
++
++/* valid baudrates */
++#define CONFIG_SYS_BAUDRATE_TABLE	{ 9600, 19200, 38400, 57600, 115200 }
++
++/*-----------------------------------------------------------------------
++ * Stack sizes
++ *
++ * The stack sizes are set up in start.S using the settings below
++ */
++#define CONFIG_STACKSIZE	(128*1024)	/* regular stack */
++#ifdef CONFIG_USE_IRQ
++#define CONFIG_STACKSIZE_IRQ	(4*1024)	/* IRQ stack */
++#define CONFIG_STACKSIZE_FIQ	(4*1024)	/* FIQ stack */
++#endif
++
++/*-----------------------------------------------------------------------
++ * Physical Memory Map
++ */
++#define CONFIG_NR_DRAM_BANKS	1	   /* we have 1 bank of DRAM */
++#define PHYS_SDRAM_1		0x30000000 /* SDRAM Bank #1 */
++#define PHYS_SDRAM_1_SIZE	0x04000000 /* 64 MB */
++
++#define PHYS_FLASH_1		0x00000000 /* Flash Bank #1 */
++
++#define CONFIG_SYS_FLASH_BASE		PHYS_FLASH_1
++
++/*-----------------------------------------------------------------------
++ * FLASH and environment organization
++ */
++
++#define CONFIG_AMD_LV400	1	/* uncomment this if you have a LV400 flash */
++#if 0
++#define CONFIG_AMD_LV800	1	/* uncomment this if you have a LV800 flash */
++#endif
++
++#define CONFIG_SYS_MAX_FLASH_BANKS	1	/* max number of memory banks */
++#ifdef CONFIG_AMD_LV800
++#define PHYS_FLASH_SIZE		0x00100000 /* 1MB */
++#define CONFIG_SYS_MAX_FLASH_SECT	(19)	/* max number of sectors on one chip */
++#define CONFIG_ENV_ADDR		(CONFIG_SYS_FLASH_BASE + 0x0F0000) /* addr of environment */
++#endif
++#ifdef CONFIG_AMD_LV400
++#define PHYS_FLASH_SIZE		0x00080000 /* 512KB */
++#define CONFIG_SYS_MAX_FLASH_SECT	(11)	/* max number of sectors on one chip */
++#define CONFIG_ENV_ADDR		(CONFIG_SYS_FLASH_BASE + 0x070000) /* addr of environment */
++#endif
++
++/* timeout values are in ticks */
++#define CONFIG_SYS_FLASH_ERASE_TOUT	(5*CONFIG_SYS_HZ) /* Timeout for Flash Erase */
++#define CONFIG_SYS_FLASH_WRITE_TOUT	(5*CONFIG_SYS_HZ) /* Timeout for Flash Write */
++
++#define	CONFIG_ENV_IS_IN_FLASH	1
++#define CONFIG_ENV_SIZE		0x10000	/* Total Size of Environment Sector */
++
++#endif	/* __CONFIG_H */
+diff -Nuar u-boot-2010.09/include/serial.h u-boot-2010.09-1-basic/include/serial.h
+--- u-boot-2010.09/include/serial.h	2010-09-29 05:20:55.000000000 +0800
++++ u-boot-2010.09-1-basic/include/serial.h	2015-11-16 13:12:09.992998611 +0800
+@@ -46,7 +46,7 @@
+ extern struct serial_device serial6_device;
+ #endif
+ 
+-#if defined(CONFIG_S3C2410)
++#if defined(CONFIG_S3C2410) || defined(CONFIG_S3C2440)
+ extern struct serial_device s3c24xx_serial0_device;
+ extern struct serial_device s3c24xx_serial1_device;
+ extern struct serial_device s3c24xx_serial2_device;
+diff -Nuar u-boot-2010.09/Makefile u-boot-2010.09-1-basic/Makefile
+--- u-boot-2010.09/Makefile	2010-09-29 05:20:55.000000000 +0800
++++ u-boot-2010.09-1-basic/Makefile	2015-11-16 13:12:09.993998586 +0800
+@@ -154,6 +154,7 @@
+ # load ARCH, BOARD, and CPU configuration
+ include $(obj)include/config.mk
+ export	ARCH CPU BOARD VENDOR SOC
++CROSS_COMPILE= /opt/buildroot-2012.08/arm920t/usr/bin/arm-linux-
+ 
+ # set default to nothing for native builds
+ ifeq ($(HOSTARCH),$(ARCH))
+@@ -317,6 +318,7 @@
+ 
+ $(obj)u-boot.bin:	$(obj)u-boot
+ 		$(OBJCOPY) ${OBJCFLAGS} -O binary $< $@
++		mv u-boot.bin u-boot-s3c2440.bin
+ 
+ $(obj)u-boot.ldr:	$(obj)u-boot
+ 		$(CREATE_LDR_ENV)
diff --git a/linux-bsp/patches/u-boot-serial-patch/u-boot-2010.09-2-dm9000.patch b/linux-bsp/patches/u-boot-serial-patch/u-boot-2010.09-2-dm9000.patch
new file mode 100644
index 0000000..5f2b2b0
--- /dev/null
+++ b/linux-bsp/patches/u-boot-serial-patch/u-boot-2010.09-2-dm9000.patch
@@ -0,0 +1,70 @@
+diff -Nuar u-boot-2010.09/board/lingyun/fl2440/fl2440.c u-boot-2010.09-2-dm9000/board/lingyun/fl2440/fl2440.c
+--- u-boot-2010.09/board/lingyun/fl2440/fl2440.c	2015-11-16 13:36:18.438996129 +0800
++++ u-boot-2010.09-2-dm9000/board/lingyun/fl2440/fl2440.c	2015-11-16 13:35:08.196993893 +0800
+@@ -166,6 +166,9 @@
+ #ifdef CONFIG_CS8900
+ 	rc = cs8900_initialize(0, CONFIG_CS8900_BASE);
+ #endif
++#ifdef CONFIG_DRIVER_DM9000 
++    rc = dm9000_initialize(bis);
++#endif
+ 	return rc;
+ }
+ #endif
+diff -Nuar u-boot-2010.09/drivers/net/dm9000x.c u-boot-2010.09-2-dm9000/drivers/net/dm9000x.c
+--- u-boot-2010.09/drivers/net/dm9000x.c	2010-09-29 05:20:55.000000000 +0800
++++ u-boot-2010.09-2-dm9000/drivers/net/dm9000x.c	2015-11-16 13:35:08.199994163 +0800
+@@ -364,7 +364,7 @@
+ 	while (!(phy_read(1) & 0x20)) {	/* autonegation complete bit */
+ 		udelay(1000);
+ 		i++;
+-		if (i == 10000) {
++		if (i == 2000) { /* Modify by guowenxue */
+ 			printf("could not establish link\n");
+ 			return 0;
+ 		}
+diff -Nuar u-boot-2010.09/include/configs/fl2440.h u-boot-2010.09-2-dm9000/include/configs/fl2440.h
+--- u-boot-2010.09/include/configs/fl2440.h	2015-11-16 13:36:18.441996228 +0800
++++ u-boot-2010.09-2-dm9000/include/configs/fl2440.h	2015-11-16 13:35:08.199994163 +0800
+@@ -58,10 +58,15 @@
+ /*
+  * Hardware drivers
+  */
+-#define CONFIG_NET_MULTI
+-#define CONFIG_CS8900		/* we have a CS8900 on-board */
+-#define CONFIG_CS8900_BASE	0x19000300
+-#define CONFIG_CS8900_BUS16	/* the Linux driver does accesses as shorts */
++#define CONFIG_NET_MULTI            1
++#define CONFIG_NET_RETRY_COUNT      20
++#define CONFIG_DRIVER_DM9000        1
++#define CONFIG_DM9000_BASE          0x20000300  /*  nGCS4 */
++#define DM9000_IO                   CONFIG_DM9000_BASE
++#define DM9000_DATA                 (CONFIG_DM9000_BASE+4)
++#define CONFIG_DM9000_USE_16BIT     1
++#define CONFIG_DM9000_NO_SROM       1
++#undef CONFIG_DM9000_DEBUG
+ 
+ /*
+  * select serial console configuration
+@@ -97,16 +102,14 @@
+ #define CONFIG_CMD_CACHE
+ #define CONFIG_CMD_DATE
+ #define CONFIG_CMD_ELF
++#define CONFIG_CMD_PING
+ 
+ 
+ #define CONFIG_BOOTDELAY	2
+-/*#define CONFIG_BOOTARGS	"root=ramfs devfs=mount console=ttySA0,9600" */
+-/*#define CONFIG_ETHADDR	08:00:3e:26:0a:5b */
+-#define CONFIG_NETMASK          255.255.255.0
+-#define CONFIG_IPADDR		10.0.0.110
+-#define CONFIG_SERVERIP		10.0.0.1
+-/*#define CONFIG_BOOTFILE	"elinos-lart" */
+-/*#define CONFIG_BOOTCOMMAND	"tftp; bootm" */
++#define CONFIG_ETHADDR      08:00:3e:26:0a:5b 
++#define CONFIG_NETMASK      255.255.255.0
++#define CONFIG_IPADDR       192.168.1.168
++#define CONFIG_SERVERIP     192.168.1.2
+ 
+ #if defined(CONFIG_CMD_KGDB)
+ #define CONFIG_KGDB_BAUDRATE	115200		/* speed to run kgdb serial port */
diff --git a/linux-bsp/patches/u-boot-serial-patch/u-boot-2010.09-3-nand.patch b/linux-bsp/patches/u-boot-serial-patch/u-boot-2010.09-3-nand.patch
new file mode 100644
index 0000000..e2d6a20
--- /dev/null
+++ b/linux-bsp/patches/u-boot-serial-patch/u-boot-2010.09-3-nand.patch
@@ -0,0 +1,190 @@
+diff -Nuar u-boot-2010.09/board/lingyun/fl2440/Makefile u-boot-2010.09-3-nand/board/lingyun/fl2440/Makefile
+--- u-boot-2010.09/board/lingyun/fl2440/Makefile	2015-11-16 13:35:08.197993985 +0800
++++ u-boot-2010.09-3-nand/board/lingyun/fl2440/Makefile	2015-11-16 13:37:57.298995667 +0800
+@@ -25,7 +25,7 @@
+ 
+ LIB	= $(obj)lib$(BOARD).a
+ 
+-COBJS	:= fl2440.o nand_read.o flash.o
++COBJS	:= fl2440.o nand_read.o
+ SOBJS	:= lowlevel_init.o
+ 
+ SRCS	:= $(SOBJS:.o=.S) $(COBJS:.o=.c)
+diff -Nuar u-boot-2010.09/common/cmd_nand.c u-boot-2010.09-3-nand/common/cmd_nand.c
+--- u-boot-2010.09/common/cmd_nand.c	2010-09-29 05:20:55.000000000 +0800
++++ u-boot-2010.09-3-nand/common/cmd_nand.c	2015-11-16 13:37:57.298995667 +0800
+@@ -148,6 +148,11 @@
+ #if defined(CONFIG_CMD_MTDPARTS)
+ out:
+ #endif
++    /* If the size is not aligment, then let it's page alignment */
++    if(0 != (*size%nand->writesize)) 
++    {
++        *size = (*size / nand->writesize + 1) * nand->writesize;  
++    }
+ 	printf("device %d ", idx);
+ 	if (*size == nand->size)
+ 		puts("whole chip\n");
+diff -Nuar u-boot-2010.09/drivers/mtd/nand/s3c2410_nand.c u-boot-2010.09-3-nand/drivers/mtd/nand/s3c2410_nand.c
+--- u-boot-2010.09/drivers/mtd/nand/s3c2410_nand.c	2010-09-29 05:20:55.000000000 +0800
++++ u-boot-2010.09-3-nand/drivers/mtd/nand/s3c2410_nand.c	2015-11-16 13:37:57.298995667 +0800
+@@ -24,6 +24,7 @@
+ #include <asm/arch/s3c24x0_cpu.h>
+ #include <asm/io.h>
+ 
++#if defined(CONFIG_S3C2410)
+ #define S3C2410_NFCONF_EN          (1<<15)
+ #define S3C2410_NFCONF_512BYTE     (1<<14)
+ #define S3C2410_NFCONF_4STEP       (1<<13)
+@@ -36,6 +37,20 @@
+ #define S3C2410_ADDR_NALE 4
+ #define S3C2410_ADDR_NCLE 8
+ 
++#elif defined(CONFIG_S3C2440)
++#define S3C2410_NFCONT_EN          (1<<0)
++#define S3C2410_NFCONT_INITECC     (1<<4)
++#define S3C2410_NFCONT_nFCE        (1<<1)
++#define S3C2410_NFCONT_MAINECCLOCK (1<<5)
++#define S3C2410_NFCONF_TACLS(x)    ((x)<<12)
++#define S3C2410_NFCONF_TWRPH0(x)   ((x)<<8)
++#define S3C2410_NFCONF_TWRPH1(x)   ((x)<<4)
++
++#define S3C2410_ADDR_NALE 0x08
++#define S3C2410_ADDR_NCLE 0x0c
++#endif
++ulong IO_ADDR_W = CONFIG_SYS_NAND_BASE;
++
+ #ifdef CONFIG_NAND_SPL
+ 
+ /* in the early stage of NAND flash booting, printf() is not available */
+@@ -59,25 +74,31 @@
+ 	debugX(1, "hwcontrol(): 0x%02x 0x%02x\n", cmd, ctrl);
+ 
+ 	if (ctrl & NAND_CTRL_CHANGE) {
+-		ulong IO_ADDR_W = (ulong)nand;
++		IO_ADDR_W = (ulong)nand;
+ 
+ 		if (!(ctrl & NAND_CLE))
+ 			IO_ADDR_W |= S3C2410_ADDR_NCLE;
+ 		if (!(ctrl & NAND_ALE))
+ 			IO_ADDR_W |= S3C2410_ADDR_NALE;
+ 
+-		chip->IO_ADDR_W = (void *)IO_ADDR_W;
++		//chip->IO_ADDR_W = (void *)IO_ADDR_W;
+ 
+ 		if (ctrl & NAND_NCE)
+-			writel(readl(&nand->NFCONF) & ~S3C2410_NFCONF_nFCE,
+-			       &nand->NFCONF);
++#if defined(CONFIG_S3C2410)
++			writel(readl(&nand->NFCONF) & ~S3C2410_NFCONF_nFCE, &nand->NFCONF);
++#elif defined(CONFIG_S3C2440)
++            writel(readl(&nand->NFCONT) & ~S3C2410_NFCONT_nFCE, &nand->NFCONT);
++#endif
+ 		else
+-			writel(readl(&nand->NFCONF) | S3C2410_NFCONF_nFCE,
+-			       &nand->NFCONF);
++#if defined(CONFIG_S3C2410)
++			writel(readl(&nand->NFCONF) | S3C2410_NFCONF_nFCE, &nand->NFCONF);
++#elif defined(CONFIG_S3C2440)
++            writel(readl(&nand->NFCONT) | S3C2410_NFCONT_nFCE, &nand->NFCONT);
++#endif
+ 	}
+ 
+ 	if (cmd != NAND_CMD_NONE)
+-		writeb(cmd, chip->IO_ADDR_W);
++        writeb(cmd, (void *)IO_ADDR_W);
+ }
+ 
+ static int s3c2410_dev_ready(struct mtd_info *mtd)
+@@ -92,7 +113,11 @@
+ {
+ 	struct s3c2410_nand *nand = s3c2410_get_base_nand();
+ 	debugX(1, "s3c2410_nand_enable_hwecc(%p, %d)\n", mtd, mode);
++#if defined(CONFIG_S3C2410)
+ 	writel(readl(&nand->NFCONF) | S3C2410_NFCONF_INITECC, &nand->NFCONF);
++#elif defined(CONFIG_S3C2440)
++    writel(readl(&nand->NFCONT) | S3C2410_NFCONT_INITECC, &nand->NFCONT);
++#endif
+ }
+ 
+ static int s3c2410_nand_calculate_ecc(struct mtd_info *mtd, const u_char *dat,
+@@ -132,6 +157,7 @@
+ 
+ 	writel(readl(&clk_power->CLKCON) | (1 << 4), &clk_power->CLKCON);
+ 
++#if defined(CONFIG_S3C2410)
+ 	/* initialize hardware */
+ 	twrph0 = 3;
+ 	twrph1 = 0;
+@@ -145,6 +171,20 @@
+ 
+ 	/* initialize nand_chip data structure */
+ 	nand->IO_ADDR_R = nand->IO_ADDR_W = (void *)&nand_reg->NFDATA;
++#elif defined(CONFIG_S3C2440) 
++    twrph0 = 4; 
++    twrph1 = 2; 
++    tacls = 0; 
++    cfg = 0;
++    cfg |= S3C2410_NFCONF_TACLS(tacls - 1);
++    cfg |= S3C2410_NFCONF_TWRPH0(twrph0 - 1);
++    cfg |= S3C2410_NFCONF_TWRPH1(twrph1 - 1);
++    writel(cfg, &nand_reg->NFCONF); 
++    cfg = (0<<13)|(0<<12)|(0<<10)|(0<<9)|(0<<8)|(0<<6)|(0<<5)|(1<<4)|(0<<1)|(1<<0);
++    writel(cfg, &nand_reg->NFCONT);
++    /*  initialize nand_chip data structure */
++    nand->IO_ADDR_R = nand->IO_ADDR_W = (void *)&nand_reg->NFDATA;
++#endif
+ 
+ 	nand->select_chip = NULL;
+ 
+diff -Nuar u-boot-2010.09/include/configs/fl2440.h u-boot-2010.09-3-nand/include/configs/fl2440.h
+--- u-boot-2010.09/include/configs/fl2440.h	2015-11-16 13:35:08.199994163 +0800
++++ u-boot-2010.09-3-nand/include/configs/fl2440.h	2015-11-16 13:37:57.298995667 +0800
+@@ -103,6 +103,7 @@
+ #define CONFIG_CMD_DATE
+ #define CONFIG_CMD_ELF
+ #define CONFIG_CMD_PING
++#define CONFIG_CMD_NAND
+ 
+ 
+ #define CONFIG_BOOTDELAY	2
+@@ -159,11 +160,15 @@
+ 
+ #define CONFIG_SYS_FLASH_BASE		PHYS_FLASH_1
+ 
++#define CONFIG_SYS_NO_FLASH         1
++#undef  CONFIG_CMD_IMLS
++
+ /*-----------------------------------------------------------------------
+  * FLASH and environment organization
+  */
+-
++#ifndef CONFIG_SYS_NO_FLASH
+ #define CONFIG_AMD_LV400	1	/* uncomment this if you have a LV400 flash */
++#endif
+ #if 0
+ #define CONFIG_AMD_LV800	1	/* uncomment this if you have a LV800 flash */
+ #endif
+@@ -184,7 +189,22 @@
+ #define CONFIG_SYS_FLASH_ERASE_TOUT	(5*CONFIG_SYS_HZ) /* Timeout for Flash Erase */
+ #define CONFIG_SYS_FLASH_WRITE_TOUT	(5*CONFIG_SYS_HZ) /* Timeout for Flash Write */
+ 
++#ifndef CONFIG_SYS_NO_FLASH
+ #define	CONFIG_ENV_IS_IN_FLASH	1
+ #define CONFIG_ENV_SIZE		0x10000	/* Total Size of Environment Sector */
++#endif
++
++#if defined(CONFIG_CMD_NAND) 
++#define CONFIG_NAND_S3C2410 
++#define CONFIG_S3C2410_NAND_SKIP_BAD  1 
++#define CONFIG_SYS_NAND_BASE          0x4E000000 
++#define CONFIG_SYS_MAX_NAND_DEVICE    1   /* Max number of NAND devices */ 
++#define CONFIG_SYS_NAND_MAX_CHIPS     1
++#define CONFIG_MTD_NAND_VERIFY_WRITE 
++
++#define CONFIG_ENV_IS_IN_NAND   1 
++#define CONFIG_ENV_OFFSET       0X60000 
++#define CONFIG_ENV_SIZE         0x20000 /* Total Size of Environment Sector */ 
++#endif  /*   CONFIG_CMD_NAND */ 
+ 
+ #endif	/* __CONFIG_H */
diff --git a/linux-bsp/patches/u-boot-serial-patch/u-boot-2010.09-4-linux.patch b/linux-bsp/patches/u-boot-serial-patch/u-boot-2010.09-4-linux.patch
new file mode 100644
index 0000000..c635445
--- /dev/null
+++ b/linux-bsp/patches/u-boot-serial-patch/u-boot-2010.09-4-linux.patch
@@ -0,0 +1,91 @@
+diff -Nuar u-boot-2010.09/board/lingyun/fl2440/fl2440.c u-boot-2010.09-4-linux/board/lingyun/fl2440/fl2440.c
+--- u-boot-2010.09/board/lingyun/fl2440/fl2440.c	2015-11-16 13:35:08.196993893 +0800
++++ u-boot-2010.09-4-linux/board/lingyun/fl2440/fl2440.c	2015-11-16 13:42:01.101997521 +0800
+@@ -132,8 +132,8 @@
+ 	gpio->GPHCON = 0x002AFAAA;
+ 	gpio->GPHUP = 0x000007FF;
+ 
+-	/* arch number of SMDK2410-Board */
+-	gd->bd->bi_arch_number = MACH_TYPE_SMDK2410;
++	/* arch number of MINI2440-Board */
++	gd->bd->bi_arch_number = MACH_TYPE_MINI2440; /* Modify by guowenxue  */
+ 
+ 	/* adress of boot parameters */
+ 	gd->bd->bi_boot_params = 0x30000100;
+diff -Nuar u-boot-2010.09/common/env_common.c u-boot-2010.09-4-linux/common/env_common.c
+--- u-boot-2010.09/common/env_common.c	2010-09-29 05:20:55.000000000 +0800
++++ u-boot-2010.09-4-linux/common/env_common.c	2015-11-16 13:53:40.179995044 +0800
+@@ -59,6 +59,30 @@
+ #ifdef	CONFIG_BOOTCOMMAND
+ 	"bootcmd="	CONFIG_BOOTCOMMAND		"\0"
+ #endif
++#ifdef CONFIG_BBL_COMMAND /* Add by guowenxue, burn u-boot image */
++   "bbl="  CONFIG_BBL_COMMAND      "\0"
++#endif
++#ifdef CONFIG_BLX_COMMAND /* Add by guowenxue, burn linux kernel image */
++   "blx="  CONFIG_BLX_COMMAND      "\0"
++#endif
++#ifdef CONFIG_BARGS_INITRAMFS /* Add by guowenxue, bootargs for initramfs rootfs  */
++   "bargs_initramfs="   CONFIG_BARGS_INITRAMFS     "\0"
++#endif
++#ifdef CONFIG_BURN_UBIFS   /* Add by guowenxue, burn UBIFS root filesystem image */
++    "bubifs=" CONFIG_BURN_UBIFS "\0" 
++#endif 
++#ifdef CONFIG_BARGS_UBIFS /* Add by guowenxue, bootargs for ubifs rootfs  */
++   "bargs_ubifs="   CONFIG_BARGS_UBIFS     "\0"
++#endif
++#ifdef CONFIG_BURN_JFFS2   /* Add by guowenxue, burn JFFS2 root filesystem image */
++    "bjffs2=" CONFIG_BURN_JFFS2 "\0" 
++#endif
++#ifdef CONFIG_BARGS_JFFS2 /* Add by guowenxue, bootargs for jffs2 rootfs  */
++   "bargs_jffs2="   CONFIG_BARGS_JFFS2     "\0"
++#endif
++#ifdef CONFIG_TFTPBOOT_COMMAND /* Add by guowenxue, tftp boot linux system */
++   "tb="   CONFIG_TFTPBOOT_COMMAND     "\0"
++#endif
+ #ifdef	CONFIG_RAMBOOTCOMMAND
+ 	"ramboot="	CONFIG_RAMBOOTCOMMAND		"\0"
+ #endif
+diff -Nuar u-boot-2010.09/include/configs/fl2440.h u-boot-2010.09-4-linux/include/configs/fl2440.h
+--- u-boot-2010.09/include/configs/fl2440.h	2015-11-16 13:37:57.298995667 +0800
++++ u-boot-2010.09-4-linux/include/configs/fl2440.h	2015-11-16 13:59:13.913995331 +0800
+@@ -112,6 +112,20 @@
+ #define CONFIG_IPADDR       192.168.1.168
+ #define CONFIG_SERVERIP     192.168.1.2
+ 
++
++#define CONFIG_BBL_COMMAND     "tftp 30008000 u-boot-s3c2440.bin;nand erase 0 100000;nand write 30008000 0 60000"
++#define CONFIG_BLX_COMMAND     "tftp 30008000 linuxrom-s3c2440.bin;nand erase 100000 F00000;nand write 30008000 100000 D00000"
++#define CONFIG_TFTPBOOT_COMMAND "tftp 30008000 linuxrom-s3c2440.bin; bootm 30008000"
++#define CONFIG_BURN_JFFS2      "tftp 30800000 jffs2-$cpu.rootfs;nand erase 1000000 4000000;nand write 30800000 3800000 $filesize"
++#define CONFIG_BURN_UBIFS      "tftp 30800000 ubifs-$cpu.rootfs;nand erase 1000000 4000000;nand write 30800000 8800000 $filesize"
++
++
++#define CONFIG_BARGS_INITRAMFS  "console=ttyS0,115200 mem=64M rw loglevel=7"
++#define CONFIG_BARGS_JFFS2      "console=ttyS0,115200 root=/dev/mtdblock2 rootfstype=jffs2 init=/linuxrc mem=64M rw noinitrd loglevel=7"
++#define CONFIG_BARGS_UBIFS      "console=ttyS0,115200 ubi.mtd=2 root=ubi0:rootfs rootwait rootfstype=ubifs init=/linuxrc mem=64M noinitrd rw loglevel=7"
++#define CONFIG_BOOTARGS        CONFIG_BARGS_INITRAMFS
++#define CONFIG_BOOTCOMMAND     "nand read 30008000 100000 D00000; bootm 30008000"
++
+ #if defined(CONFIG_CMD_KGDB)
+ #define CONFIG_KGDB_BAUDRATE	115200		/* speed to run kgdb serial port */
+ /* what's this ? it's not used anywhere */
+@@ -207,4 +221,18 @@
+ #define CONFIG_ENV_SIZE         0x20000 /* Total Size of Environment Sector */ 
+ #endif  /*   CONFIG_CMD_NAND */ 
+ 
++#define CONFIG_SETUP_MEMORY_TAGS
++#define CONFIG_INITRD_TAG
++#define CONFIG_CMDLINE_TAG
++
++#define CONFIG_SYS_HUSH_PARSER
++#define CONFIG_SYS_PROMPT_HUSH_PS2   "> "
++
++#define CONFIG_CMDLINE_EDITING
++#ifdef CONFIG_CMDLINE_EDITING
++#undef CONFIG_AUTO_COMPLETE
++#else
++#define CONFIG_AUTO_COMPLETE
++#endif
++
+ #endif	/* __CONFIG_H */
diff --git a/linux-bsp/tarballs/rootfs.tar.bz2 b/linux-bsp/tarballs/rootfs.tar.bz2
new file mode 100644
index 0000000..96de69b
--- /dev/null
+++ b/linux-bsp/tarballs/rootfs.tar.bz2
Binary files differ

--
Gitblit v1.9.1