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,
+ ¬Dir, &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, ¬Dir, &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, ¬Dir, &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,
+ ¬OldDir, &oldLoop);
+ newdir = yaffsfs_FindDirectory(NULL, newPath, &newname, 0,
+ ¬NewDir, &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, ¬Dir, &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, ¬Dir, &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, ¬Dir, &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, ¬Dir, &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, ¬Dir, &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, ¬Dir, &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, ¬Dir, &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, ¬Dir, &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, ¬Dir, &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, ¬Dir, &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, ¬Dir, &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, ¬Dir, &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, ¬DirObj, &objLoop);
+ lnk = yaffsfs_FindObject(NULL, linkpath, 0, 0, NULL, NULL, NULL);
+ lnk_dir = yaffsfs_FindDirectory(NULL, linkpath, &newname,
+ 0, ¬DirLnk, &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